/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* DeploymentDescriptorModel.java
*
* Created on December 3, 2001, 3:43 PM
*/
package com.sun.jdo.spi.persistence.support.ejb.model;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import com.sun.enterprise.deployment.*;
import com.sun.jdo.api.persistence.model.RuntimeModel;
import com.sun.jdo.spi.persistence.support.ejb.model.util.NameMapper;
import com.sun.jdo.api.persistence.model.jdo.RelationshipElement;
import com.sun.jdo.api.persistence.model.jdo.PersistenceFieldElement;
import com.sun.jdo.spi.persistence.utility.JavaTypeHelper;
/** This is a subclass of RuntimeModel which uses the deployment descriptor
* to augment the java metadata for a non-existent persistence-capable
* java/class file. It is primarily used at ejbc time, though it could be
* used at any time as long as sufficient mapping and deployment descriptor
* information is available. See the javadoc for individual methods below
* for differences and translations between persistence-capable and ejb
* names and behavior. There are different answers to methods depending
* on whether they are called on the persistence-capable or the ejb. These
* are primarily for the handling of serializable, non-primitive, non-wrapper
* type fields: isByteArray, getFieldType (returning byte array),
* isPersistentTypeAllowed and isPersistentAllowed (returning true) which
* return answers about the byte array when called on the persistence-capable
* and return answers about the serializable type when called on the ejb.
*
* @author Rochelle Raccah
*/
public class DeploymentDescriptorModel extends RuntimeModel
{
private ClassLoader _classLoader;
private NameMapper _nameMapper;
/**
* Signature with CVS keyword substitution for identifying the generated code
*/
public static final String SIGNATURE = "$RCSfile: DeploymentDescriptorModel.java,v $ $Revision: 1.3 $"; //NOI18N
/** Creates a new instance of DeploymentDescriptorModel
* @param nameMapper the name mapper to be used as a helper for
* translation between persistence class and ejb names.
* @param classLoader the class loader object which is used for the
* application.
*/
public DeploymentDescriptorModel (NameMapper nameMapper,
ClassLoader classLoader)
{
super();
_classLoader = classLoader;
_nameMapper = nameMapper;
}
private ClassLoader getClassLoader () { return _classLoader; }
private NameMapper getNameMapper () { return _nameMapper; }
/** Returns the input stream with the supplied resource name found with
* the supplied class name. This method overrides the one in
* RuntimeModel to enforce using the class loader provided at construction
* time instead of the one specified in this method.
* @param className the fully qualified name of the class which will be
* used as a base to find the resource
* @param classLoader the class loader used to find mapping information
* This parameter is ignored in this implementation - instead the
* class loader supplied at construction time is used.
* @param resourceName the name of the resource to be found
* @return the input stream for the specified resource, <code>null</code>
* if an error occurs or none exists
*/
protected BufferedInputStream getInputStreamForResource (String className,
ClassLoader classLoader, String resourceName)
{
return super.getInputStreamForResource(
className, getClassLoader(), resourceName);
}
/** Returns the name of the second to top (top excluding java.lang.Object)
* superclass for the given class name. This method overrides the one in
* RuntimeModel in order to return the supplied className if it
* represents a persistence-capable class. This is because the
* persistence-capable classes don't mirror the inheritance
* hierarchy of the ejbs.
* @param className the fully qualified name of the class to be checked
* @return the top non-Object superclass for className,
* <code>className</code> if an error occurs or none exists
*/
protected String findPenultimateSuperclass (String className)
{
return (isPCClassName(className) ? className :
super.findPenultimateSuperclass(className));
}
/** Returns the name of the superclass for the given class name. This
* method overrides the one in RuntimeModel in order to return
* java.lang.Object if the supplied className represents a
* persistence-capable class. This is because the persistence-capable
* classes don't mirror the inheritance hierarchy of the ejbs.
* @param className the fully qualified name of the class to be checked
* @return the superclass for className, <code>null</code> if an error
* occurs or none exists
*/
protected String getSuperclass (String className)
{
return (isPCClassName(className) ? "java.lang.Object" : // NOI18N
super.getSuperclass(className));
}
/** Creates a file with the given base file name and extension
* parallel to the supplied class (if it does not yet exist). This
* method overrides the one in RuntimeModel and throws
* UnsupportedOperationException in the case where the file
* doesn't yet exist. If the file exists (even if it has
* just been "touched"), this method will return that output stream,
* but it is not capable of using the supplied class as a sibling location.
* @param className the fully qualified name of the class
* @param baseFileName the name of the base file
* @param extension the file extension
* @return the output stream for the specified resource, <code>null</code>
* if an error occurs or none exists
* @exception IOException if there is some error creating the file
*/
protected BufferedOutputStream createFile (String className, String baseFileName,
String extension) throws IOException
{
BufferedOutputStream outputStream =
super.createFile(className, baseFileName, extension);
if (outputStream != null)
return outputStream;
throw new UnsupportedOperationException();
}
/** Deletes the file with the given file name which is parallel
* to the supplied class. This method overrides the one in RuntimeModel
* and throws UnsupportedOperationException.
* @param className the fully qualified name of the class
* @param fileName the name of the file
* @exception IOException if there is some error deleting the file
*/
protected void deleteFile (String className, String fileName)
throws IOException
{
throw new UnsupportedOperationException();
}
/** Returns the class element with the specified className. If the
* specified className represents a persistence-capable class, the
* abstract bean class for the corresponding ejb is always returned
* (even if there is a Class object available for the
* persistence-capable). If there is an ejb name and an abstract bean
* class with the same name, the abstract bean class which is associated
* with the ejb will be returned, not the abstract bean class which
* corresponds to the supplied name (directly). If the specified
* className represents a persistence-capable key class name, the
* corresponding bean's key class is returned.
* @param className the fully qualified name of the class to be checked
* @param classLoader the class loader used to find mapping information
* @return the class element for the specified className
*/
public Object getClass (final String className,
final ClassLoader classLoader)
{
String testClass = className;
// translate the class name to corresponding ejb name's abstract
// bean or key class if necessary
if (className != null)
{
NameMapper nameMapper = getNameMapper();
String ejbName =
(isPCClassName(className) ? getEjbName(className) : className);
if (nameMapper.isEjbName(ejbName))
testClass = nameMapper.getAbstractBeanClassForEjbName(ejbName);
else
{
String keyClass =
nameMapper.getKeyClassForPersistenceKeyClass(className);
if (keyClass != null)
{
// if it's a pk field of type primitive, byte[],
// or other array, return the primitive class or a
// dummy class
if (NameMapper.PRIMARY_KEY_FIELD ==
getPersistenceKeyClassType(className))
{
if (isPrimitive(keyClass))
return JavaTypeHelper.getPrimitiveClass(keyClass);
if (isByteArray(keyClass) || keyClass.endsWith("[]"))
return byte[].class;
}
testClass = keyClass;
}
}
}
return super.getClass(testClass, getClassLoader());
}
/** Returns a wrapped constructor element for the specified argument types
* in the class with the specified name. If the specified class name is
* a persistence-capable key class name which corresponds to a bean
* with an unknown primary key class a dummy constructor will also be
* returned. Types are specified as type names for primitive type
* such as int, float or as fully qualified class names.
* @param className the name of the class which contains the constructor
* to be checked
* @param argTypeNames the fully qualified names of the argument types
* @return the constructor element
* @see #getClass
*/
public Object getConstructor (final String className, String[] argTypeNames)
{
Object returnObject = null;
if ((NameMapper.PRIMARY_KEY_FIELD ==
getPersistenceKeyClassType(className)) &&
argTypeNames.equals(NO_ARGS))
{
returnObject = new MemberWrapper(className, null, Modifier.PUBLIC,
(Class)getClass(className));
}
if (returnObject == null)
{
returnObject = super.getConstructor(className, argTypeNames);
if (returnObject instanceof Constructor) // wrap it
returnObject = new MemberWrapper((Constructor)returnObject);
}
return returnObject;
}
/** Returns a wrapped method element for the specified method name and
* argument types in the class with the specified name. If the
* specified className represents a persistence-capable class and
* the requested methodName is readObject or writeObject, a dummy
* method will be returned. Similarly, if the specified class name is
* a persistence-capable key class name which corresponds to a bean
* with an unknown primary key class or a primary key field (in both
* cases there is no user defined primary key class) and the requested
* method is equals or hashCode, a dummy method will also be returned.
* Types are specified as type names for primitive type such as int,
* float or as fully qualified class names. Note, the method does not
* return inherited methods.
* @param className the name of the class which contains the method
* to be checked
* @param methodName the name of the method to be checked
* @param argTypeNames the fully qualified names of the argument types
* @return the method element
* @see #getClass
*/
public Object getMethod (final String className, final String methodName,
String[] argTypeNames)
{
int keyClassType = getPersistenceKeyClassType(className);
Object returnObject = null;
if (isPCClassName(className))
{
if ((methodName.equals("readObject") && // NOI18N
argTypeNames.equals(READ_OBJECT_ARGS)) ||
(methodName.equals("writeObject") && // NOI18N
argTypeNames.equals(WRITE_OBJECT_ARGS)))
{
returnObject = new MemberWrapper(methodName,
Void.TYPE, Modifier.PRIVATE, (Class)getClass(className));
}
}
if ((NameMapper.UNKNOWN_KEY_CLASS == keyClassType) ||
(NameMapper.PRIMARY_KEY_FIELD == keyClassType))
{
if (methodName.equals("equals") && // NOI18N
argTypeNames.equals(EQUALS_ARGS))
{
returnObject = new MemberWrapper(methodName,
Boolean.TYPE, Modifier.PUBLIC, (Class)getClass(className));
}
else if (methodName.equals("hashCode") && // NOI18N
argTypeNames.equals(NO_ARGS))
{
returnObject = new MemberWrapper(methodName,
Integer.TYPE, Modifier.PUBLIC, (Class)getClass(className));
}
}
if (returnObject == null)
{
returnObject = super.getMethod(className, methodName, argTypeNames);
if (returnObject instanceof Method) // wrap it
returnObject = new MemberWrapper((Method)returnObject);
}
return returnObject;
}
/** Returns the inherited method element for the specified method
* name and argument types in the class with the specified name.
* Types are specified as type names for primitive type such as
* int, float or as fully qualified class names. Note that the class
* with the specified className is not checked for this method, only
* superclasses are checked. This method overrides the one in
* Model in order to do special handling for a persistence-capable key
* class name which corresponds to a bean with a primary key
* field. In that case, we don't want to climb the inheritance
* of the primary key field type.
* @param className the name of the class which contains the method
* to be checked
* @param methodName the name of the method to be checked
* @param argTypeNames the fully qualified names of the argument types
* @return the method element
* @see #getClass
*/
public Object getInheritedMethod (String className, String methodName,
String[] argTypeNames)
{
// If the class name corresponds to a pk field (which means that
// there is no user defined primary key class, we don't want to
// climb the inheritance hierarchy, we only process this class.
return ((NameMapper.PRIMARY_KEY_FIELD ==
getPersistenceKeyClassType(className)) ?
getMethod(className, methodName, argTypeNames) :
super.getInheritedMethod(className, methodName, argTypeNames));
}
/** Returns a list of names of all the declared field elements in the
* class with the specified name. If the specified className represents
* a persistence-capable class, the list of field names from the
* corresponding ejb is returned (even if there is a Class object
* available for the persistence-capable).
* @param className the fully qualified name of the class to be checked
* @return the names of the field elements for the specified class
*/
public List getFields (final String className)
{
final EjbCMPEntityDescriptor descriptor = getCMPDescriptor(className);
String testClass = className;
if (descriptor != null) // need to get names of ejb fields
{
Iterator iterator = descriptor.getFieldDescriptors().iterator();
List returnList = new ArrayList();
while (iterator.hasNext())
returnList.add(((FieldDescriptor)iterator.next()).getName());
return returnList;
}
else
{
NameMapper nameMapper = getNameMapper();
String ejbName =
nameMapper.getEjbNameForPersistenceKeyClass(className);
switch (getPersistenceKeyClassType(className))
{
// find the field names we need in the corresponding
// ejb key class
case NameMapper.USER_DEFINED_KEY_CLASS:
testClass = nameMapper.getKeyClassForEjbName(ejbName);
break;
// find the field name we need in the abstract bean
case NameMapper.PRIMARY_KEY_FIELD:
return Arrays.asList(new String[]{
getCMPDescriptor(ejbName).
getPrimaryKeyFieldDesc().getName()});
// find the field name we need in the persistence capable
case NameMapper.UNKNOWN_KEY_CLASS:
String pcClassName =
nameMapper.getPersistenceClassForEjbName(ejbName);
PersistenceFieldElement[] fields =
getPersistenceClass(pcClassName).getFields();
int i, count = ((fields != null) ? fields.length : 0);
for (i = 0; i < count; i++)
{
PersistenceFieldElement pfe = fields[i];
if (pfe.isKey())
return Arrays.asList(new String[]{pfe.getName()});
}
break;
}
}
return super.getFields(testClass);
}
/** Returns a list of names of all the field elements in the
* class with the specified name. This list includes the inherited
* fields. If the specified className represents a
* persistence-capable class, the list of field names from the
* corresponding ejb is returned (even if there is a Class object
* available for the persistence-capable). This method overrides
* the one in Model in order to do special handling for a
* persistence-capable key class name which corresponds to a bean
* with a primary key field. In that case, we don't want to
* climb the inheritance hierarchy of the primary key field type.
* @param className the fully qualified name of the class to be checked
* @return the names of the field elements for the specified class
*/
public List getAllFields (String className)
{
// If the class name corresponds to a pk field (which means that
// there is no user defined primary key class, we don't want to
// climb the inheritance hierarchy, we only process this class.
return ((NameMapper.PRIMARY_KEY_FIELD ==
getPersistenceKeyClassType(className)) ? getFields(className) :
super.getAllFields(className));
}
/** Returns a wrapped field element for the specified fieldName in the
* class with the specified className. If the specified className
* represents a persistence-capable class, a field representing the
* field in the abstract bean class for the corresponding ejb is always
* returned (even if there is a Field object available for the
* persistence-capable). If there is an ejb name and an abstract bean
* class with the same name, the abstract bean class which is associated
* with the ejb will be used, not the abstract bean class which
* corresponds to the supplied name (directly).
* @param className the fully qualified name of the class which contains
* the field to be checked
* @param fieldName the name of the field to be checked
* @return the wrapped field element for the specified fieldName
*/
public Object getField (final String className, String fieldName)
{
String testClass = className;
Object returnObject = null;
if (className != null)
{
NameMapper nameMapper = getNameMapper();
boolean isPCClass = isPCClassName(className);
boolean isPKClassName = false;
String searchClassName = className;
String searchFieldName = fieldName;
// translate the class name & field names to corresponding
// ejb name's abstract bean equivalents if necessary
if (isPCClass)
{
searchFieldName = nameMapper.
getEjbFieldForPersistenceField(className, fieldName);
searchClassName = getEjbName(className);
}
else // check if it's a pk class without a user defined key class
{
String ejbName =
nameMapper.getEjbNameForPersistenceKeyClass(className);
switch (getPersistenceKeyClassType(className))
{
// find the field we need in the corresponding
// abstract bean (translated below from ejbName)
case NameMapper.PRIMARY_KEY_FIELD:
testClass = ejbName;
searchClassName = ejbName;
isPKClassName = true;
break;
// find the field we need by called updateFieldWrapper
// below which handles the generated field for the
// unknown key class - need to use the
// persistence-capable class name and flag to call that
// code, so we configure it here
case NameMapper.UNKNOWN_KEY_CLASS:
testClass = nameMapper.
getPersistenceClassForEjbName(ejbName);
isPCClass = true;
isPKClassName = true;
break;
}
}
if (nameMapper.isEjbName(searchClassName))
{
searchClassName = nameMapper.
getAbstractBeanClassForEjbName(searchClassName);
}
returnObject = super.getField(searchClassName, searchFieldName);
if (returnObject == null) // try getting it from the descriptor
returnObject = getFieldWrapper(testClass, searchFieldName);
else if (returnObject instanceof Field) // wrap it
returnObject = new MemberWrapper((Field)returnObject);
if (isPCClass)
{
returnObject = updateFieldWrapper(
(MemberWrapper)returnObject, testClass, fieldName);
}
// when asking for these fields as part of the
// persistence-capable's key class, we need to represent the
// public modifier which will be generated in the inner class
if (isPKClassName && (returnObject instanceof MemberWrapper))
((MemberWrapper)returnObject)._modifiers = Modifier.PUBLIC;
}
return returnObject;
}
/** Returns the field type for the specified fieldName in the class
* with the specified className. This method is overrides the one in
* Model in order to do special handling for non-collection relationship
* fields. If it's a generated relationship that case, the returned
* MemberWrapper from getField contains a type of the abstract bean and
* it's impossible to convert that into the persistence capable class name, so here
* that case is detected, and if found, the ejb name is extracted and
* used to find the corresponding persistence capable class. For a
* relationship which is of type of the local interface, we do the
* conversion from local interface to persistence-capable class. In the
* case of a collection relationship (generated or not), the superclass'
* implementation which provides the java type is sufficient.
* @param className the fully qualified name of the class which contains
* the field to be checked
* @param fieldName the name of the field to be checked
* @return the field type for the specified fieldName
*/
public String getFieldType (String className, String fieldName)
{
String returnType = super.getFieldType(className, fieldName);
if (!isCollection(returnType) && isPCClassName(className))
{
NameMapper nameMapper = getNameMapper();
String ejbName =
nameMapper.getEjbNameForPersistenceClass(className);
String ejbField =
nameMapper.getEjbFieldForPersistenceField(className, fieldName);
if (nameMapper.isGeneratedEjbRelationship(ejbName, ejbField))
{
String[] inverse =
nameMapper.getEjbFieldForGeneratedField(ejbName, ejbField);
returnType = nameMapper.
getPersistenceClassForEjbName(inverse[0]);
}
if (nameMapper.isLocalInterface(returnType))
{
returnType = nameMapper.getPersistenceClassForLocalInterface(
className, fieldName, returnType);
}
}
return returnType;
}
/** Returns the string representation of declaring class of
* the specified member element. Note, the member element is
* either a class element as returned by getClass, a field element
* as returned by getField, a constructor element as returned by
* getConstructor, or a method element as returned by getMethod
* executed on the same model instance. This implementation expects
* the member element to be a reflection instance or a wrapped member
* instance.
* @param memberElement the member element to be checked
* @return the string representation of the declaring class of
* the specified memberElement
* @see #getClass
* @see #getField
* @see #getConstructor
* @see #getMethod
*/
public String getDeclaringClass (Object memberElement)
{
if ((memberElement != null) && (memberElement instanceof MemberWrapper))
{
Class classElement =
((MemberWrapper)memberElement).getDeclaringClass();
return ((classElement != null) ? classElement.getName() : null);
}
return super.getDeclaringClass(memberElement);
}
/** Returns the modifier mask for the specified member element.
* Note, the member element is either a class element as returned by
* getClass, a member wrapper element as returned by getField or
* getMethod, a constructor element as returned by getConstructor
* executed on the same model instance.
* This implementation expects the member element being a reflection
* instance or a wrapped member instance.
* @param memberElement the member element to be checked
* @return the modifier mask for the specified memberElement
* @see java.lang.reflect.Modifier
* @see #getClass
* @see #getField
* @see #getConstructor
* @see #getMethod
*/
public int getModifiers (Object memberElement)
{
if ((memberElement != null) && (memberElement instanceof MemberWrapper))
return ((MemberWrapper)memberElement).getModifiers();
return super.getModifiers(memberElement);
}
/** Returns the modifier mask for the specified className. This method
* overrides the one in Model to strip out the abstract modifier when
* the persistence capable class is represented by the abstract bean.
* It also adds the static modifier when the specified class represents
* the persistence capable key class which will be generated.
* @param className the fully qualified name of the class to be checked
* @return the modifier mask for the specified class
* @see java.lang.reflect.Modifier
*/
public int getModifiersForClass (String className)
{
int modifiers = super.getModifiersForClass(className);
if (isPCClassName(className))
modifiers &= ~Modifier.ABSTRACT;
else if (getNameMapper().
getKeyClassForPersistenceKeyClass(className) != null)
{
modifiers |= Modifier.STATIC;
}
return modifiers;
}
/** Determines if the specified className and fieldName pair represent a
* field which has a type which is valid for key fields. Valid key
* field types include non-collection SCOs (wrappers, Date, Time, etc.)
* and primitives for user defined key classes. This method overrides
* the one in Model in order to do special handling for a
* persistence-capable key class name which corresponds to a bean
* with a primary key field. In that case, we want to restrict the
* list of allowable types not to include primitives.
* @param className the fully qualified name of the class which contains
* the field to be checked
* @param fieldName the name of the field to be checked
* @return <code>true</code> if this field name represents a field
* with a valid type for a key field; <code>false</code> otherwise.
*/
public boolean isValidKeyType (String className, String fieldName)
{
return (((NameMapper.PRIMARY_KEY_FIELD ==
getPersistenceKeyClassType(className)) &&
isPrimitive(className, fieldName)) ? false :
super.isValidKeyType(className, fieldName));
}
/** Returns the Class type of the specified element.
* If element denotes a field, it returns the type of the field.
* If element denotes a method, it returns the return type of the method.
* Note, element is either a field element as returned by getField, or a
* method element as returned by getMethod executed on the same model
* instance.
* @param element the element to be checked
* @return the Class type of the element
* @see #getField
* @see RuntimeModel#getMethod
*/
protected Class getTypeObject (Object element)
{
Class type = super.getTypeObject(element);
if ((element != null) && (element instanceof MemberWrapper))
type = ((MemberWrapper)element).getType();
return type;
}
/**
* This method returns the class loader used to find mapping information
* for the specified className. This implementation overrides the one in
* RuntimeModel so that it always returns the ClassLoader provided at
* construction time.
* @param className the fully qualified name of the class to be checked
* @param classLoader the class loader used to find mapping information
* @return the class loader used to find mapping information for the
* specified className
*/
protected ClassLoader findClassLoader (String className,
ClassLoader classLoader)
{
return getClassLoader();
}
// return true if a conversion to a ejb class is needed for
// java.lang.reflect metadata
private boolean isPCClassName (String className)
{
return (getEjbName(className) != null);
}
private String getEjbName (String className)
{
return getNameMapper().getEjbNameForPersistenceClass(className);
}
private EjbCMPEntityDescriptor getCMPDescriptor (String className)
{
String descriptorName = (isPCClassName(className) ?
getEjbName(className) : className);
return getNameMapper().getDescriptorForEjbName(descriptorName);
}
private int getPersistenceKeyClassType (String className)
{
int returnValue = -1;
if (getCMPDescriptor(className) == null)
{
NameMapper nameMapper = getNameMapper();
String ejbName =
nameMapper.getEjbNameForPersistenceKeyClass(className);
if (ejbName != null)
returnValue = nameMapper.getKeyClassTypeForEjbName(ejbName);
}
return returnValue;
}
private MemberWrapper getFieldWrapper (String className, String fieldName)
{
EjbCMPEntityDescriptor descriptor = getCMPDescriptor(className);
MemberWrapper returnObject = null;
if (descriptor != null)
{
PersistenceDescriptor persistenceDescriptor =
descriptor.getPersistenceDescriptor();
if (persistenceDescriptor != null)
{
Class fieldType = null;
try
{
fieldType = persistenceDescriptor.getTypeFor(fieldName);
}
catch (RuntimeException e)
{
// fieldType will be null - there is no such field
}
returnObject = ((fieldType == null) ? null :
new MemberWrapper(fieldName, fieldType,
Modifier.PRIVATE, (Class)getClass(className)));
}
}
return returnObject;
}
private MemberWrapper updateFieldWrapper (MemberWrapper returnObject,
String className, String fieldName)
{
NameMapper nameMapper = getNameMapper();
if (returnObject == null)
{
// can't call isPersistent or isKey because that calls
// hasField which calls getField and that would end up
// in an endless loop
PersistenceFieldElement field =
getPersistenceFieldInternal(className, fieldName);
if (field != null)
{
String ejbName = getEjbName(className);
String ejbFieldName = nameMapper.
getEjbFieldForPersistenceField(className, fieldName);
// Check if this is the auto-added field for unknown pk
// support. If so, return a private field of type Long.
if (field.isKey() && (ejbName != null) &&
(nameMapper.getKeyClassTypeForEjbName(ejbName) ==
NameMapper.UNKNOWN_KEY_CLASS))
{
returnObject = new MemberWrapper(ejbFieldName,
Long.class, Modifier.PRIVATE,
(Class)getClass(className));
}
// Check if this is the auto-added field for 2 way managed rels
// support. If so, return a private field of type according to
// cardinality of the relationship.
else if ((field instanceof RelationshipElement) &&
nameMapper.isGeneratedEjbRelationship(ejbName,
ejbFieldName))
{
RelationshipElement rel = (RelationshipElement)field;
Class classType = null;
// figure out the type
if (rel.getUpperBound() > 1)
classType = java.util.HashSet.class;
else
{
String[] inverse = nameMapper.
getEjbFieldForGeneratedField(ejbName, ejbFieldName);
classType = (Class)getClass(inverse[0]);
}
if (classType != null)
{
returnObject = new MemberWrapper(ejbFieldName,
classType, Modifier.PRIVATE,
(Class)getClass(className));
}
}
// Check if this is the auto-added version field.
// If so, return a private field of type long.
else if (ejbFieldName.startsWith(
NameMapper.GENERATED_VERSION_FIELD_PREFIX) &&
nameMapper.isGeneratedField(ejbName, ejbFieldName))
{
returnObject = new MemberWrapper(ejbFieldName,
Long.TYPE, Modifier.PRIVATE,
(Class)getClass(className));
}
}
}
// if the field in the corresponding ejb is a serializable,
// non-primitive, non-wrapper type, convert it to byte[] here
if (!isPersistentTypeAllowed(getType(returnObject),
getClassLoader()) && isSerializable(returnObject))
{
returnObject.setType(byte[].class);
}
return returnObject;
}
private class MemberWrapper
{
private String _name;
private Class _type;
private int _modifiers;
private Class _declaringClass;
private MemberWrapper (Member member)
{
this(member.getName(), ((member instanceof Field) ?
((Field)member).getType() : ((member instanceof Method) ?
((Method)member).getReturnType() : null)),
member.getModifiers(), member.getDeclaringClass());
}
private MemberWrapper (String name, Class type, int modifiers,
Class declaringClass)
{
_name = name;
_type = type;
_modifiers = modifiers;
_declaringClass = declaringClass;
}
private Class getType () { return _type; }
private void setType (Class type) { _type = type; }
private String getName () { return _name; }
private int getModifiers () { return _modifiers; }
private Class getDeclaringClass () { return _declaringClass; }
/** Returns a string representation of this object.
* @return a string reprentation of the member wrapper object.
*/
public String toString () { return getName(); }
}
}
|