Package org.apache.jdo.impl.model.java.reflection

Source Code of org.apache.jdo.impl.model.java.reflection.ReflectionJavaType

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.jdo.impl.model.java.reflection;

import java.util.Map;
import java.util.HashMap;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.jdo.impl.model.java.PredefinedType;
import org.apache.jdo.impl.model.java.BaseReflectionJavaType;
import org.apache.jdo.impl.model.java.JavaPropertyImpl;
import org.apache.jdo.model.ModelFatalException;
import org.apache.jdo.model.java.JavaField;
import org.apache.jdo.model.java.JavaMethod;
import org.apache.jdo.model.java.JavaModel;
import org.apache.jdo.model.java.JavaProperty;
import org.apache.jdo.model.java.JavaType;
import org.apache.jdo.model.jdo.JDOClass;
import org.apache.jdo.model.jdo.JDOField;

/**
* A reflection based JavaType implementation used at runtime. 
* The implementation takes <code>java.lang.Class</code> and
* <code>java.lang.reflect.Field</code> instances to get Java related
* metadata about types and fields.
*
* @author Michael Bouschen
* @since JDO 1.1
* @version JDO 2.0
*/
public class ReflectionJavaType
    extends BaseReflectionJavaType
{
    /** The declaring JavaModel instance. */
    protected final ReflectionJavaModel declaringJavaModel;

    /** Flag indicating whether the superclass is checked already. */
    private boolean superclassUnchecked = true;

    /** Flag indicating whether the JDOClass info is retrieved already. */
    private boolean jdoClassUnchecked = true;

    /** The JDO metadata, if this type represents a pc class. */
    private JDOClass jdoClass;

    /** Map of JavaField instances, key is the field name. */
    protected Map declaredJavaFields = new HashMap();

    /** Map of JavaProperty instances, key is the property name. */
    protected Map declaredJavaProperties = new HashMap();

    /** Flag indicating whether thsi JavaTYpe has been introspected. */
    private boolean introspected = false;

    /** Constructor. */
    public ReflectionJavaType(Class clazz,
        ReflectionJavaModel declaringJavaModel)
    {
        // Pass null as the superclass to the super call. This allows lazy
        // evaluation of the superclass (see getSuperclass implementation).
        super(clazz, null);
        this.declaringJavaModel = declaringJavaModel;
    }

    /**
     * Determines if this JavaType object represents an array type.
     * @return <code>true</code> if this object represents an array type;
     * <code>false</code> otherwise.
     */
    public boolean isArray()
    {
        return clazz.isArray();
    }

    /**
     * Returns <code>true</code> if this JavaType represents a persistence
     * capable class.
     * <p>
     * A {@link org.apache.jdo.model.ModelFatalException} indicates a
     * problem accessing the JDO meta data for this JavaType.
     * @return <code>true</code> if this JavaType represents a persistence
     * capable class; <code>false</code> otherwise.
     * @exception ModelFatalException if there is a problem accessing the
     * JDO metadata
     */
    public boolean isPersistenceCapable()
        throws ModelFatalException
    {
        return (getJDOClass() != null);
    }

    /**
     * Returns the JavaType representing the superclass of the entity
     * represented by this JavaType. If this JavaType represents either the
     * Object class, an interface, a primitive type, or <code>void</code>,
     * then <code>null</code> is returned. If this object represents an
     * array class then the JavaType instance representing the Object class
     * is returned. 
     * @return the superclass of the class represented by this JavaType.
     */
    public synchronized JavaType getSuperclass()
    {
        if (superclassUnchecked) {
            superclassUnchecked = false;
            superclass = getJavaTypeForClass(clazz.getSuperclass());
        }
        return superclass;
    }

    /**
     * Returns the JDOClass instance if this JavaType represents a
     * persistence capable class. The method returns <code>null</code>,
     * if this JavaType does not represent a persistence capable class.
     * <p>
     * A {@link org.apache.jdo.model.ModelFatalException} indicates a
     * problem accessing the JDO meta data for this JavaType.
     * @return the JDOClass instance if this JavaType represents a
     * persistence capable class; <code>null</code> otherwise.
     * @exception ModelFatalException if there is a problem accessing the
     * JDO metadata
     */
    public synchronized JDOClass getJDOClass()
        throws ModelFatalException
    {
        if (jdoClassUnchecked) {
            jdoClassUnchecked = false;
            jdoClass = declaringJavaModel.getJDOModel().getJDOClass(getName());
        }
        return jdoClass;
    }
    /**
     * Returns the JavaType representing the component type of an array.
     * If this JavaType does not represent an array type this method
     * returns <code>null</code>.
     * @return the JavaType representing the component type of this
     * JavaType if this class is an array; <code>null</code> otherwise.
     */
    public JavaType getArrayComponentType()
    {
        JavaType componentType = null;
        if (isArray()) {
            Class componentClass = clazz.getComponentType();
            if (componentClass != null)
                componentType = getJavaTypeForClass(componentClass);
        }
        return componentType;
    }

    /**
     * Returns a JavaField instance that reflects the field with the
     * specified name of the class or interface represented by this
     * JavaType instance. The method returns <code>null</code>, if the
     * class or interface (or one of its superclasses) does not have a
     * field with that name.
     * @param fieldName the name of the field
     * @return the JavaField instance for the specified field in this class
     * or <code>null</code> if there is no such field.
     */
    public JavaField getJavaField(String fieldName)
    {
        JavaField javaField = getDeclaredJavaField(fieldName);
        if (javaField == null) {
            // check superclass
            JavaType superclass = getSuperclass();
            if ((superclass != null) &&
                (superclass != PredefinedType.objectType)) {
                javaField = superclass.getJavaField(fieldName);
            }
        }
        return javaField;
    }

    /**
     * Returns an array of JavaField instances representing the declared
     * fields of the class represented by this JavaType instance. Note, this
     * method does not return JavaField instances representing inherited
     * fields.
     * @return an array of declared JavaField instances.
     */
    public JavaField[] getDeclaredJavaFields()
    {
        introspectClass();
        return (JavaField[]) declaredJavaFields.values().toArray(
            new JavaField[0]);
    }
   
     /**
     * Returns a JavaProperty instance that reflects the property with the
     * specified name of the class or interface represented by this
     * JavaType instance. The method returns <code>null</code>, if the
     * class or interface (or one of its superclasses) does not have a
     * field with that name.
     * @param name the name of the property
     * @return the JavaProperty instance for the specified property in this
     * class or <code>null</code> if there is no such property.
     */
    public JavaProperty getJavaProperty(String name)
    {
        JavaProperty javaProperty = getDeclaredJavaProperty(name);
        if (javaProperty == null) {
            // check superclass
            JavaType superclass = getSuperclass();
            if ((superclass != null) &&
                (superclass != PredefinedType.objectType)) {
                javaProperty = superclass.getJavaProperty(name);
            }
        }
        return javaProperty;
    }

    /**
     * Returns an array of JavaProperty instances representing the declared
     * properties of the class represented by this JavaType instance. Note,
     * this method does not return JavaField instances representing inherited
     * properties.
     * @return an array of declared JavaField instances.
     */
    public JavaProperty[] getDeclaredJavaProperties()
    {
        introspectClass();
        return (JavaProperty[]) declaredJavaProperties.values().toArray(
            new JavaProperty[0]);
    }

    // ===== Methods not specified in JavaType =====

    /**
     * Returns a JavaField instance that reflects the declared field with
     * the specified name of the class or interface represented by this
     * JavaType instance. The method returns <code>null</code>, if the
     * class or interface does not declared a field with that name. It does
     * not check whether one of its superclasses declares such a field.
     * @param fieldName the name of the field
     * @return the JavaField instance for the specified field in this class
     */
    public synchronized JavaField getDeclaredJavaField(String fieldName)
    {
        JavaField javaField = (JavaField)declaredJavaFields.get(fieldName);
        if (javaField == null) {
            JDOClass jdoClass = getJDOClass();
            if (jdoClass != null) {
                // pc class => look for JDOField first
                if (jdoClass.getDeclaredField(fieldName) != null) {
                    // Use JDO metadata and create a JavaField skeleton to
                    // avoid unnecessary reflection access.
                    javaField = newJavaFieldInstance(fieldName, null);
                    declaredJavaFields.put(fieldName, javaField);
                }
            }
           
            // if no field info check reflection
            if (javaField == null) {
                Field field = ReflectionJavaField.getDeclaredFieldPrivileged(
                    clazz, fieldName);
                if (field != null) {
                    javaField = newJavaFieldInstance(field);
                    declaredJavaFields.put(fieldName, javaField);
                }
            }
        }
        return javaField;  
    }

    /**
     * Returns a JavaProperty instance that reflects the declared property
     * with the specified name of the class or interface represented by this
     * JavaType instance. The method returns <code>null</code>, if the
     * class or interface does not declared a property with that name. It does
     * not check whether one of its superclasses declares such a property.
     * @param name the name of the property
     * @return the JavaField instance for the specified property in this class
     */
    public JavaProperty getDeclaredJavaProperty(String name)
    {
        introspectClass();
        return (JavaProperty)declaredJavaProperties.get(name);
    }

    /**
     * Returns a JavaType instance for the specified Class object.
     * This method provides a hook such that ReflectionJavaType subclasses can
     * implement their own mapping of Class objects to JavaType instances.
     */
    public JavaType getJavaTypeForClass(Class clazz)
    {
        return declaringJavaModel.getDeclaringJavaModelFactory().getJavaType(clazz);
    }

    /**
     * Creates a new JavaProperty instance and adds it to the list of
     * declared properties of this class.
     * @param name the name of the property
     * @param getter the getter method
     * @param setter the setter method
     * @param type the ytpe of the property
     * @return a new JavaProperty declared by this class
     */
    public synchronized JavaProperty createJavaProperty(
        String name, JavaMethod getter, JavaMethod setter, JavaType type)
        throws ModelFatalException
    {
        JavaProperty javaProperty =
            newJavaPropertyInstance(name, getter, setter, type);
        declaredJavaProperties.put(name, javaProperty);
        return javaProperty;
    }

    /**
     * Creates a new JavaMethod instance.
     * @param method the java.lang.reflect.Method instance
     * @return a new JavaMethod declared by this class
     */
    public JavaMethod createJavaMethod(Method method)
    {
        return newJavaMethodInstance(method);
    }

    /**
     * Creates a new instance of the JavaField implementation class.
     * <p>
     * This implementation returns a <code>ReflectionJavaField</code>
     * instance.
     * @return a new JavaField instance.
     */
    protected JavaField newJavaFieldInstance(String fieldName, JavaType type)
    {
        return new ReflectionJavaField(fieldName, type, this);
    }
   
    /**
     * Creates a new instance of the JavaField implementation class.
     * <p>
     * This implementation returns a <code>ReflectionJavaField</code>
     * instance.
     * @return a new JavaField instance.
     */
    protected JavaField newJavaFieldInstance(Field field)
    {
        return new ReflectionJavaField(field, this);
    }
   
    /**
     * Creates a new instance of the JavaProperty implementation class.
     * <p>
     * This implementation returns a <code>JavaPropertyImpl</code>
     * instance.
     * @return a new JavaProperty instance.
     */
    protected JavaProperty newJavaPropertyInstance(String name,
            JavaMethod getter, JavaMethod setter, JavaType type)
        throws ModelFatalException
    {
        return new JavaPropertyImpl(name, getter, setter, type, this);
    }

    /**
     * Creates a new instance of the JavaMethod implementation class.
     * <p>
     * This implementation returns a <code>ReflectionJavaMethod</code>
     * instance.
     * @return a new JavaMethod instance.
     */
    protected JavaMethod newJavaMethodInstance(Method method)
    {
        return new ReflectionJavaMethod(method, this);
    }

    /**
     * Helper method to introspect the class and set the declared fields and
     * properties.
     */
    protected synchronized void introspectClass()
    {
        if (introspected)
            // has been introspected before => return;
            return;
       
        introspected = true;
       
        new ReflectionJavaTypeIntrospector().addDeclaredJavaProperties(this);

        // now get all the declared fields
        Field[] fields = ReflectionJavaField.getDeclaredFieldsPrivileged(clazz);
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            String fieldName = field.getName();
            if (declaredJavaFields.get(fieldName) == null) {
                JavaField javaField = newJavaFieldInstance(field);
                declaredJavaFields.put(fieldName, javaField);
            }
        }
    }
TOP

Related Classes of org.apache.jdo.impl.model.java.reflection.ReflectionJavaType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.