Coverage Report - org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDirectImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
PersistentFieldDirectImpl
N/A
N/A
4
 
 1  
 package org.apache.ojb.broker.metadata.fieldaccess;
 2  
 
 3  
 /* Copyright 2003-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import java.lang.reflect.Field;
 19  
 import java.util.List;
 20  
 
 21  
 import org.apache.ojb.broker.metadata.MetadataException;
 22  
 import org.apache.ojb.broker.util.ClassHelper;
 23  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 24  
 
 25  
 /**
 26  
  * This {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField} implementation
 27  
  * is the high-speed version of the access strategies.
 28  
  * <br/>
 29  
  * It does not cooperate with an AccessController,
 30  
  * but accesses the fields directly. This implementation persistent
 31  
  * attributes don't need getters and setters
 32  
  * and don't have to be declared public or protected. Only the the
 33  
  * metadata field names have to match the class fields.
 34  
  *
 35  
  * @version $Id: PersistentFieldDirectImpl.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
 36  
  */
 37  
 public class PersistentFieldDirectImpl extends PersistentFieldBase
 38  
 {
 39  
     private static final long serialVersionUID = -5458024240998909205L;
 40  
 
 41  
     private transient boolean isInitialized;
 42  
     private transient List fieldsList;
 43  
     private transient Field field;
 44  
     private transient boolean nonNested;
 45  
 
 46  
     public PersistentFieldDirectImpl()
 47  
     {
 48  
     }
 49  
 
 50  
     public PersistentFieldDirectImpl(Class type, String fieldname)
 51  
     {
 52  
         super(type, fieldname);
 53  
     }
 54  
 
 55  
     public Class getType()
 56  
     {
 57  
         return getField().getType();
 58  
     }
 59  
 
 60  
     /**
 61  
      * Returns the underlying field object.
 62  
      * If parameter <tt>setAccessible</tt> is true the
 63  
      * field access checking was suppressed.
 64  
      */
 65  
     protected Field getField()
 66  
     {
 67  
         // make sure class was initialized
 68  
         if (!isInitialized)
 69  
         {
 70  
             /*
 71  
             first we build a graph of fields for nested fields support,
 72  
             but for best performance on non-nested fields we also keep
 73  
             the latest field separate and set a 'is nested' flag.
 74  
             */
 75  
             fieldsList = getFieldGraph(makeAccessible());
 76  
             field = (Field) fieldsList.get(fieldsList.size() - 1);
 77  
             nonNested = fieldsList.size() == 1;
 78  
             isInitialized = true;
 79  
         }
 80  
         return field;
 81  
     }
 82  
 
 83  
     private List getFieldsList()
 84  
     {
 85  
         // make sure class was initialized
 86  
         if (!isInitialized) getField();
 87  
         return fieldsList;
 88  
     }
 89  
 
 90  
     protected boolean isNestedField()
 91  
     {
 92  
         return !nonNested;
 93  
     }
 94  
 
 95  
     /**
 96  
      * do not override this method, have a look at {@link #setValueFor(java.lang.reflect.Field, Object, Object)}
 97  
      */
 98  
     public void set(Object target, Object value) throws MetadataException
 99  
     {
 100  
         // if target null, we have nothing to do
 101  
         if(target == null) return;
 102  
         Object current = target;
 103  
         if (isNestedField())
 104  
         {
 105  
             List fields = getFieldsList();
 106  
             int size = fields.size() - 1;
 107  
             Field field;
 108  
             for (int i = 0; i < size; i++)
 109  
             {
 110  
                 field = (Field) fields.get(i);
 111  
                 Object attribute;
 112  
                 try
 113  
                 {
 114  
                     attribute = getValueFrom(field, current);
 115  
                 }
 116  
                 catch (Exception e)
 117  
                 {
 118  
                     throw new MetadataException("Can't read field '" + field.getName() + "' of type " + field.getType().getName(), e);
 119  
                 }
 120  
                 if (attribute != null || value != null)
 121  
                 {
 122  
                     // if the intermediary nested object is null, we have to create
 123  
                     // a new instance to set the value
 124  
                     if (attribute == null)
 125  
                     {
 126  
                         try
 127  
                         {
 128  
                             attribute = ClassHelper.newInstance(field.getType());
 129  
                         }
 130  
                         catch (Exception e)
 131  
                         {
 132  
                             throw new MetadataException("Can't create nested object of type '"
 133  
                                     + field.getType() + "' for field '"
 134  
                                     + field.getName() + "'", e);
 135  
                         }
 136  
                     }
 137  
                     try
 138  
                     {
 139  
                         //field.set(current, attribute);
 140  
                         setValueFor(field, current, attribute);
 141  
                     }
 142  
                     //catch (IllegalAccessException e)
 143  
                     catch (Exception e)
 144  
                     {
 145  
                         throw new MetadataException("Can't set nested object of type '"
 146  
                                     + field.getType() + "' for field '"
 147  
                                     + field.getName() + "'", e);
 148  
                     }
 149  
                 }
 150  
                 else
 151  
                 {
 152  
                     return;
 153  
                 }
 154  
                 current = attribute;
 155  
             }
 156  
         }
 157  
         setValueFor(getField(), current, value);
 158  
     }
 159  
 
 160  
     /**
 161  
      * do not override this method, have a look at {@link #getValueFrom(java.lang.reflect.Field, Object)}
 162  
      */
 163  
     public Object get(Object target) throws MetadataException
 164  
     {
 165  
         Object result = target;
 166  
         if (isNestedField())
 167  
         {
 168  
             List fields = getFieldsList();
 169  
             for (int i = 0; i < fields.size(); i++)
 170  
             {
 171  
                 if (result == null) break;
 172  
                 result = getValueFrom((Field) fields.get(i), result);
 173  
             }
 174  
         }
 175  
         else
 176  
         {
 177  
             result = result != null ? getValueFrom(getField(), result) : null;
 178  
         }
 179  
         return result;
 180  
     }
 181  
 
 182  
 
 183  
 
 184  
     protected Object getValueFrom(Field field, Object target)
 185  
     {
 186  
         try
 187  
         {
 188  
             return field.get(ProxyHelper.getRealObject(target));
 189  
             // TODO: don't make costly proxy test on field level use
 190  
             // return field.get(target);
 191  
         }
 192  
         catch (IllegalAccessException e)
 193  
         {
 194  
             throw new MetadataException(
 195  
                     "IllegalAccess error reading field: " +
 196  
                     (field != null ? field.getName() : null) + " from object: "
 197  
                     + (target != null ? target.getClass().getName() : null), e);
 198  
         }
 199  
         catch (IllegalArgumentException e)
 200  
         {
 201  
             throw new MetadataException(
 202  
                     "IllegalArgument error reading field: " +
 203  
                     buildErrorGetMsg(target, field), e);
 204  
         }
 205  
     }
 206  
 
 207  
     protected void setValueFor(Field field, Object target, final Object value)
 208  
     {
 209  
         try
 210  
         {
 211  
             /**
 212  
              * MBAIRD
 213  
              * we need to be able to set values to null. We can only set something to null if
 214  
              * the type is not a primitive (assignable from Object).
 215  
              */
 216  
             // thanks to Tomasz Wysocki for this trick
 217  
             if ((value != null) || !field.getType().isPrimitive())
 218  
             {
 219  
                 field.set(ProxyHelper.getRealObject(target), value);
 220  
                 // TODO: don't make costly proxy test on field level use
 221  
                 // field.set(target, value);
 222  
             }
 223  
         }
 224  
         catch (NullPointerException ignored)
 225  
         {
 226  
             getLog().info("Target object '" + (target != null ? target.getClass().getName() : null)
 227  
                     + "' for field '" + (field != null ? field.getName() : null)
 228  
                     + "' of type '" + (field != null ? field.getType().getName() : null)
 229  
                     + "' seems to be null. Can't write into null.", ignored);
 230  
         }
 231  
         catch (Exception e)
 232  
         {
 233  
             getLog().error("while set field: " + buildErrorSetMsg(target, value, field));
 234  
             throw new MetadataException("IllegalAccess error setting field:" +
 235  
                     (field != null ? field.getName() : null) + " in object:" + target.getClass().getName(), e);
 236  
         }
 237  
     }
 238  
 
 239  
     /**
 240  
      * This implementation returns always 'true'.
 241  
      */
 242  
     protected boolean makeAccessible()
 243  
     {
 244  
         return true;
 245  
     }
 246  
 
 247  
     /**
 248  
      * Always returns 'false'.
 249  
      * @see org.apache.ojb.broker.metadata.fieldaccess.PersistentField#usesAccessorsAndMutators
 250  
      */
 251  
     public boolean usesAccessorsAndMutators()
 252  
     {
 253  
         return false;
 254  
     }
 255  
 }