Save This Page
Home » jdo2-model-2.3-ea-src » org.apache.jdo.impl.model.java.reflection » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  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   package org.apache.jdo.impl.model.java.reflection;
   19   
   20   import java.util.Map;
   21   import java.util.HashMap;
   22   
   23   import java.lang.reflect.Field;
   24   import java.lang.reflect.Method;
   25   
   26   import org.apache.jdo.impl.model.java.PredefinedType;
   27   import org.apache.jdo.impl.model.java.BaseReflectionJavaType;
   28   import org.apache.jdo.impl.model.java.JavaPropertyImpl;
   29   import org.apache.jdo.model.ModelFatalException;
   30   import org.apache.jdo.model.java.JavaField;
   31   import org.apache.jdo.model.java.JavaMethod;
   32   import org.apache.jdo.model.java.JavaModel;
   33   import org.apache.jdo.model.java.JavaProperty;
   34   import org.apache.jdo.model.java.JavaType;
   35   import org.apache.jdo.model.jdo.JDOClass;
   36   import org.apache.jdo.model.jdo.JDOField;
   37   
   38   /**
   39    * A reflection based JavaType implementation used at runtime.  
   40    * The implementation takes <code>java.lang.Class</code> and
   41    * <code>java.lang.reflect.Field</code> instances to get Java related
   42    * metadata about types and fields. 
   43    *
   44    * @author Michael Bouschen
   45    * @since JDO 1.1
   46    * @version JDO 2.0
   47    */
   48   public class ReflectionJavaType
   49       extends BaseReflectionJavaType
   50   {
   51       /** The declaring JavaModel instance. */
   52       protected final ReflectionJavaModel declaringJavaModel;
   53   
   54       /** Flag indicating whether the superclass is checked already. */
   55       private boolean superclassUnchecked = true;
   56   
   57       /** Flag indicating whether the JDOClass info is retrieved already. */
   58       private boolean jdoClassUnchecked = true;
   59   
   60       /** The JDO metadata, if this type represents a pc class. */
   61       private JDOClass jdoClass;
   62   
   63       /** Map of JavaField instances, key is the field name. */
   64       protected Map declaredJavaFields = new HashMap();
   65   
   66       /** Map of JavaProperty instances, key is the property name. */
   67       protected Map declaredJavaProperties = new HashMap();
   68   
   69       /** Flag indicating whether thsi JavaTYpe has been introspected. */
   70       private boolean introspected = false;
   71   
   72       /** Constructor. */
   73       public ReflectionJavaType(Class clazz, 
   74           ReflectionJavaModel declaringJavaModel)
   75       {
   76           // Pass null as the superclass to the super call. This allows lazy
   77           // evaluation of the superclass (see getSuperclass implementation).
   78           super(clazz, null); 
   79           this.declaringJavaModel = declaringJavaModel;
   80       }
   81   
   82       /**
   83        * Determines if this JavaType object represents an array type.
   84        * @return <code>true</code> if this object represents an array type; 
   85        * <code>false</code> otherwise.
   86        */
   87       public boolean isArray()
   88       {
   89           return clazz.isArray();
   90       }
   91   
   92       /** 
   93        * Returns <code>true</code> if this JavaType represents a persistence
   94        * capable class.
   95        * <p>
   96        * A {@link org.apache.jdo.model.ModelFatalException} indicates a
   97        * problem accessing the JDO meta data for this JavaType.
   98        * @return <code>true</code> if this JavaType represents a persistence
   99        * capable class; <code>false</code> otherwise.
  100        * @exception ModelFatalException if there is a problem accessing the
  101        * JDO metadata
  102        */
  103       public boolean isPersistenceCapable()
  104           throws ModelFatalException
  105       {
  106           return (getJDOClass() != null);
  107       }
  108   
  109       /** 
  110        * Returns the JavaType representing the superclass of the entity
  111        * represented by this JavaType. If this JavaType represents either the 
  112        * Object class, an interface, a primitive type, or <code>void</code>, 
  113        * then <code>null</code> is returned. If this object represents an
  114        * array class then the JavaType instance representing the Object class
  115        * is returned.  
  116        * @return the superclass of the class represented by this JavaType.
  117        */
  118       public synchronized JavaType getSuperclass()
  119       {
  120           if (superclassUnchecked) {
  121               superclassUnchecked = false;
  122               superclass = getJavaTypeForClass(clazz.getSuperclass());
  123           }
  124           return superclass;
  125       }
  126   
  127       /**
  128        * Returns the JDOClass instance if this JavaType represents a
  129        * persistence capable class. The method returns <code>null</code>, 
  130        * if this JavaType does not represent a persistence capable class.
  131        * <p>
  132        * A {@link org.apache.jdo.model.ModelFatalException} indicates a
  133        * problem accessing the JDO meta data for this JavaType.
  134        * @return the JDOClass instance if this JavaType represents a
  135        * persistence capable class; <code>null</code> otherwise.
  136        * @exception ModelFatalException if there is a problem accessing the
  137        * JDO metadata
  138        */
  139       public synchronized JDOClass getJDOClass()
  140           throws ModelFatalException
  141       {
  142           if (jdoClassUnchecked) {
  143               jdoClassUnchecked = false;
  144               jdoClass = declaringJavaModel.getJDOModel().getJDOClass(getName());
  145           }
  146           return jdoClass;
  147       }
  148    
  149       /** 
  150        * Returns the JavaType representing the component type of an array. 
  151        * If this JavaType does not represent an array type this method
  152        * returns <code>null</code>.
  153        * @return the JavaType representing the component type of this
  154        * JavaType if this class is an array; <code>null</code> otherwise. 
  155        */ 
  156       public JavaType getArrayComponentType()
  157       {
  158           JavaType componentType = null;
  159           if (isArray()) {
  160               Class componentClass = clazz.getComponentType();
  161               if (componentClass != null)
  162                   componentType = getJavaTypeForClass(componentClass);
  163           }
  164           return componentType;
  165       }
  166   
  167       /**
  168        * Returns a JavaField instance that reflects the field with the
  169        * specified name of the class or interface represented by this
  170        * JavaType instance. The method returns <code>null</code>, if the
  171        * class or interface (or one of its superclasses) does not have a
  172        * field with that name.
  173        * @param fieldName the name of the field 
  174        * @return the JavaField instance for the specified field in this class
  175        * or <code>null</code> if there is no such field.
  176        */
  177       public JavaField getJavaField(String fieldName) 
  178       { 
  179           JavaField javaField = getDeclaredJavaField(fieldName);
  180           if (javaField == null) {
  181               // check superclass
  182               JavaType superclass = getSuperclass();
  183               if ((superclass != null) &&
  184                   (superclass != PredefinedType.objectType)) {
  185                   javaField = superclass.getJavaField(fieldName);
  186               }
  187           }
  188           return javaField;
  189       }
  190   
  191       /**
  192        * Returns an array of JavaField instances representing the declared
  193        * fields of the class represented by this JavaType instance. Note, this
  194        * method does not return JavaField instances representing inherited
  195        * fields. 
  196        * @return an array of declared JavaField instances. 
  197        */
  198       public JavaField[] getDeclaredJavaFields()
  199       {
  200           introspectClass();
  201           return (JavaField[]) declaredJavaFields.values().toArray(
  202               new JavaField[0]);
  203       }
  204       
  205        /**
  206        * Returns a JavaProperty instance that reflects the property with the
  207        * specified name of the class or interface represented by this
  208        * JavaType instance. The method returns <code>null</code>, if the
  209        * class or interface (or one of its superclasses) does not have a
  210        * field with that name.
  211        * @param name the name of the property 
  212        * @return the JavaProperty instance for the specified property in this
  213        * class or <code>null</code> if there is no such property.
  214        */
  215       public JavaProperty getJavaProperty(String name)
  216       {
  217           JavaProperty javaProperty = getDeclaredJavaProperty(name);
  218           if (javaProperty == null) {
  219               // check superclass
  220               JavaType superclass = getSuperclass();
  221               if ((superclass != null) &&
  222                   (superclass != PredefinedType.objectType)) {
  223                   javaProperty = superclass.getJavaProperty(name);
  224               }
  225           }
  226           return javaProperty;
  227       }
  228   
  229       /**
  230        * Returns an array of JavaProperty instances representing the declared
  231        * properties of the class represented by this JavaType instance. Note,
  232        * this method does not return JavaField instances representing inherited
  233        * properties. 
  234        * @return an array of declared JavaField instances. 
  235        */
  236       public JavaProperty[] getDeclaredJavaProperties()
  237       {
  238           introspectClass();
  239           return (JavaProperty[]) declaredJavaProperties.values().toArray(
  240               new JavaProperty[0]);
  241       }
  242   
  243       // ===== Methods not specified in JavaType =====
  244   
  245       /**
  246        * Returns a JavaField instance that reflects the declared field with
  247        * the specified name of the class or interface represented by this
  248        * JavaType instance. The method returns <code>null</code>, if the 
  249        * class or interface does not declared a field with that name. It does
  250        * not check whether one of its superclasses declares such a field.
  251        * @param fieldName the name of the field 
  252        * @return the JavaField instance for the specified field in this class
  253        */
  254       public synchronized JavaField getDeclaredJavaField(String fieldName)
  255       {
  256           JavaField javaField = (JavaField)declaredJavaFields.get(fieldName);
  257           if (javaField == null) {
  258               JDOClass jdoClass = getJDOClass();
  259               if (jdoClass != null) {
  260                   // pc class => look for JDOField first
  261                   if (jdoClass.getDeclaredField(fieldName) != null) {
  262                       // Use JDO metadata and create a JavaField skeleton to
  263                       // avoid unnecessary reflection access.
  264                       javaField = newJavaFieldInstance(fieldName, null);
  265                       declaredJavaFields.put(fieldName, javaField);
  266                   }
  267               }
  268               
  269               // if no field info check reflection
  270               if (javaField == null) {
  271                   Field field = ReflectionJavaField.getDeclaredFieldPrivileged(
  272                       clazz, fieldName);
  273                   if (field != null) {
  274                       javaField = newJavaFieldInstance(field);
  275                       declaredJavaFields.put(fieldName, javaField);
  276                   }
  277               }
  278           }
  279           return javaField;   
  280       }
  281   
  282       /**
  283        * Returns a JavaProperty instance that reflects the declared property
  284        * with the specified name of the class or interface represented by this
  285        * JavaType instance. The method returns <code>null</code>, if the 
  286        * class or interface does not declared a property with that name. It does
  287        * not check whether one of its superclasses declares such a property.
  288        * @param name the name of the property 
  289        * @return the JavaField instance for the specified property in this class
  290        */
  291       public JavaProperty getDeclaredJavaProperty(String name) 
  292       {
  293           introspectClass();
  294           return (JavaProperty)declaredJavaProperties.get(name);
  295       }
  296   
  297       /** 
  298        * Returns a JavaType instance for the specified Class object. 
  299        * This method provides a hook such that ReflectionJavaType subclasses can
  300        * implement their own mapping of Class objects to JavaType instances. 
  301        */
  302       public JavaType getJavaTypeForClass(Class clazz)
  303       {
  304           return declaringJavaModel.getDeclaringJavaModelFactory().getJavaType(clazz);
  305       }
  306   
  307       /** 
  308        * Creates a new JavaProperty instance and adds it to the list of
  309        * declared properties of this class.
  310        * @param name the name of the property
  311        * @param getter the getter method
  312        * @param setter the setter method
  313        * @param type the ytpe of the property
  314        * @return a new JavaProperty declared by this class
  315        */
  316       public synchronized JavaProperty createJavaProperty(
  317           String name, JavaMethod getter, JavaMethod setter, JavaType type)
  318           throws ModelFatalException
  319       {
  320           JavaProperty javaProperty = 
  321               newJavaPropertyInstance(name, getter, setter, type);
  322           declaredJavaProperties.put(name, javaProperty);
  323           return javaProperty;
  324       }
  325   
  326       /**
  327        * Creates a new JavaMethod instance.
  328        * @param method the java.lang.reflect.Method instance
  329        * @return a new JavaMethod declared by this class
  330        */
  331       public JavaMethod createJavaMethod(Method method)
  332       {
  333           return newJavaMethodInstance(method);
  334       }
  335   
  336       /**
  337        * Creates a new instance of the JavaField implementation class.
  338        * <p>
  339        * This implementation returns a <code>ReflectionJavaField</code>
  340        * instance.
  341        * @return a new JavaField instance.
  342        */
  343       protected JavaField newJavaFieldInstance(String fieldName, JavaType type) 
  344       {
  345           return new ReflectionJavaField(fieldName, type, this);
  346       }
  347       
  348       /**
  349        * Creates a new instance of the JavaField implementation class.
  350        * <p>
  351        * This implementation returns a <code>ReflectionJavaField</code>
  352        * instance.
  353        * @return a new JavaField instance.
  354        */
  355       protected JavaField newJavaFieldInstance(Field field) 
  356       {
  357           return new ReflectionJavaField(field, this);
  358       }
  359       
  360       /**
  361        * Creates a new instance of the JavaProperty implementation class.
  362        * <p>
  363        * This implementation returns a <code>JavaPropertyImpl</code>
  364        * instance.
  365        * @return a new JavaProperty instance.
  366        */
  367       protected JavaProperty newJavaPropertyInstance(String name, 
  368               JavaMethod getter, JavaMethod setter, JavaType type) 
  369           throws ModelFatalException
  370       {
  371           return new JavaPropertyImpl(name, getter, setter, type, this);
  372       }
  373   
  374       /**
  375        * Creates a new instance of the JavaMethod implementation class.
  376        * <p>
  377        * This implementation returns a <code>ReflectionJavaMethod</code>
  378        * instance.
  379        * @return a new JavaMethod instance.
  380        */
  381       protected JavaMethod newJavaMethodInstance(Method method) 
  382       {
  383           return new ReflectionJavaMethod(method, this);
  384       }
  385   
  386       /** 
  387        * Helper method to introspect the class and set the declared fields and
  388        * properties. 
  389        */
  390       protected synchronized void introspectClass() 
  391       {
  392           if (introspected)
  393               // has been introspected before => return;
  394               return;
  395           
  396           introspected = true;
  397           
  398           new ReflectionJavaTypeIntrospector().addDeclaredJavaProperties(this);
  399   
  400           // now get all the declared fields
  401           Field[] fields = ReflectionJavaField.getDeclaredFieldsPrivileged(clazz);
  402           for (int i = 0; i < fields.length; i++) {
  403               Field field = fields[i];
  404               String fieldName = field.getName();
  405               if (declaredJavaFields.get(fieldName) == null) {
  406                   JavaField javaField = newJavaFieldInstance(field);
  407                   declaredJavaFields.put(fieldName, javaField);
  408               }
  409           }
  410       }
  411   } 

Save This Page
Home » jdo2-model-2.3-ea-src » org.apache.jdo.impl.model.java.reflection » [javadoc | source]