Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
DataNucleus Core provides the primary components of a heterogenous Java persistence solution.
It supports persistence API's being layered on top of the core functionality.
/**********************************************************************
Copyright (c) 2004 Andy Jefferson and others. All rights reserved.
Licensed 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.
Contributors:
2007 Xuan Baldauf - Implement solution for issue CORE-3272
2007 Xuan Baldauf - allow users to explictly state that an array whose component type is not PC may still have PC elements. See CORE-3274
...
**********************************************************************/
package org.datanucleus.metadata;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ClassNameConstants;
import org.datanucleus.api.ApiAdapter;
import org.datanucleus.enhancement.Persistable;
import org.datanucleus.exceptions.ClassNotResolvedException;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.store.types.TypeManager;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;
/**
* Abstract representation of MetaData for a field/property of a class/interface.
* The term "member" is used to represent either a field or a method(property). The term
* property is used to represent the name after cutting off any Java-beans style "get" prefix.
* This class is extended for fields (FieldMetaData) and properties (PropertyMetaData) to provide
* the explicit support for those components.
*/
public abstract class AbstractMemberMetaData extends MetaData implements Comparable, ColumnMetaDataContainer
{
private static final long serialVersionUID = -7689828287704042919L;
/** Whether we currently allow persistence of static fields. */
public static final boolean PERSIST_STATIC = false;
/** Whether we currently allow persistence of final fields. */
public static final boolean PERSIST_FINAL = false;
/** Whether we currently allow persistence of transient fields. */
public static final boolean PERSIST_TRANSIENT = false;
/** Contains the metadata for column(s). */
protected ColumnMetaData[] columnMetaData;
/** Meta-Data of any container. */
protected ContainerMetaData containerMetaData;
/** EmbeddedMetaData. */
protected EmbeddedMetaData embeddedMetaData;
/** JoinMetaData. */
protected JoinMetaData joinMetaData;
/** ElementMetaData. */
protected ElementMetaData elementMetaData;
/** KeyMetaData. */
protected KeyMetaData keyMetaData;
/** ValueMetaData. */
protected ValueMetaData valueMetaData;
/** IndexMetaData. */
protected IndexMetaData indexMetaData;
/** The indexing value */
protected IndexedValue indexed = null;
/** UniqueMetaData. */
protected UniqueMetaData uniqueMetaData;
/** Whether to add a unique constraint. */
protected boolean uniqueConstraint = false;
/** OrderMetaData. */
protected OrderMetaData orderMetaData;
/** ForeignKeyMetaData. */
protected ForeignKeyMetaData foreignKeyMetaData;
/** default-fetch-group tag value. */
protected Boolean defaultFetchGroup;
/** column tag value. */
protected String column;
/** mapped-by tag value. */
protected String mappedBy;
/** embedded tag value. */
protected Boolean embedded;
/** Whether this field contains a reference that should be deleted when deleting this field. */
protected Boolean dependent;
/** serialized tag value. */
protected Boolean serialized;
/** cacheable tag value. */
protected boolean cacheable = true;
/** Whether to persist this relation when persisting the owning object. */
protected Boolean cascadePersist;
/** Whether to update this relation when updating the owning object. */
protected Boolean cascadeUpdate;
/** Whether to delete this relation when deleting the owning object (JPA). TODO Link this to dependent */
protected Boolean cascadeDelete;
/** Whether to detach this relation when detaching the owning object (JPA). */
protected Boolean cascadeDetach;
/** Whether to refresh this relation when refreshing the owning object (JPA). */
protected Boolean cascadeRefresh;
/** Whether to remove orphans when deleting the owning object (JPA). */
protected boolean cascadeRemoveOrphans = false;
/** load-fetch-group value. */
protected String loadFetchGroup;
/** Default recursion-depth according to proposed final draft spec, [12.7.2]. */
public static final int DEFAULT_RECURSION_DEPTH = 1;
/** Indicates the recursion-depth is not defined. Use default value. */
public static final int UNDEFINED_RECURSION_DEPTH = 0;
/** recursion-depth value. */
protected int recursionDepth = UNDEFINED_RECURSION_DEPTH;
/** Field name. */
protected final String name;
/** null-value tag value (default is NONE). */
protected NullValue nullValue = NullValue.NONE;
/** persistence-modifier tag value. */
protected FieldPersistenceModifier persistenceModifier = FieldPersistenceModifier.DEFAULT;
/** primary key tag value. */
protected Boolean primaryKey;
/** Table name for this field. */
protected String table;
/** Catalog for the table specified for this field. */
protected String catalog;
/** Schema for the table specified for this field. */
protected String schema;
/**
* The value-strategy attribute specifies the strategy used to generate
* values for the field. This attribute has the same values and meaning as
* the strategy attribute in datastoreidentity.
*/
protected IdentityStrategy valueStrategy;
/** Name of a value generator if the user wants to override the default generator. */
protected String valueGeneratorName;
/**
* If the value-strategy is sequence, the sequence attribute specifies the
* name of the sequence to use to automatically generate a value for the field.
*/
protected String sequence;
/**
* Name of the class to which this field really belongs. Will be null if the field belongs
* to the parent ClassMetaData, and will have a value if it is an overriding field.
*/
protected String className = null;
/** Cache result of {@link #getFullFieldName()}. */
protected String fullFieldName = null;
/** Field type being represented. */
protected Class type;
/** The member (field/method) being represented here. Note, this prevents Serialization. */
protected Member memberRepresented;
/** Id of the field in its class (only for fields that are managed). If the value is -1, the field is NOT managed or the object hasn't been populated. */
protected int fieldId=-1;
/** The relation type of this field (1-1, 1-N, M-N, N-1). */
protected RelationType relationType = null;
/** MetaData for the other end of a relation when this member is a bidirectional relation. This may be multiple fields if the FK is shared. */
protected AbstractMemberMetaData[] relatedMemberMetaData = null;
/** Temporary flag to signify if the field is ordered. */
protected boolean ordered = false;
// -------------------------------------------------------------------------
// These fields are only used when the MetaData is read by the parser and
// elements are dynamically added to the other elements. At runtime, "columnMetaData"
// should be used.
/** Columns ColumnMetaData */
protected List columns = new ArrayList();
/** Name of the target entity (when used with JPA MetaData on OneToOne, OneToMany etc) */
protected String targetClassName = null;
/** Wrapper for the ugly JPA "lob" so that when being populated we should make this serialised in some way. */
protected boolean storeInLob = false;
/** Placeholder for the JPA "mapsId" attribute, in case a store plugin wants to use it */
protected String mapsIdAttribute = null;
/** Placeholder for the JPA relation type ManyToOne, OneToOne etc so we can store what the user specified. */
protected String relationTypeString = null;
/** Flags for use in enhancement process [see JDO spec 21.14] */
protected byte persistenceFlags;
/**
* Convenience constructor to copy the specification from the passed member.
* This is used when we have an overriding field and we make a copy of the baseline
* member as a starting point.
* @param parent The parent
* @param mmd The member metadata to copy
*/
public AbstractMemberMetaData(MetaData parent, AbstractMemberMetaData mmd)
{
super(parent, mmd);
// Copy the simple field values
this.name = mmd.name;
this.primaryKey = mmd.primaryKey;
this.defaultFetchGroup = mmd.defaultFetchGroup;
this.column = mmd.column;
this.mappedBy = mmd.mappedBy;
this.dependent = mmd.dependent;
this.embedded = mmd.embedded;
this.serialized = mmd.serialized;
this.cascadePersist = mmd.cascadePersist;
this.cascadeUpdate = mmd.cascadeUpdate;
this.cascadeDelete = mmd.cascadeDelete;
this.cascadeDetach = mmd.cascadeDetach;
this.cascadeRefresh = mmd.cascadeRefresh;
this.nullValue = mmd.nullValue;
this.persistenceModifier = mmd.persistenceModifier;
this.table = mmd.table;
this.indexed = mmd.indexed;
this.valueStrategy = mmd.valueStrategy;
this.valueGeneratorName = mmd.valueGeneratorName;
this.sequence = mmd.sequence;
this.uniqueConstraint = mmd.uniqueConstraint;
this.loadFetchGroup = mmd.loadFetchGroup;
this.storeInLob = mmd.storeInLob;
this.mapsIdAttribute = mmd.mapsIdAttribute;
this.relationTypeString = mmd.relationTypeString;
this.column = mmd.column;
// Create copies of the object fields
if (mmd.joinMetaData != null)
{
setJoinMetaData(new JoinMetaData(mmd.joinMetaData));
}
if (mmd.elementMetaData != null)
{
setElementMetaData(new ElementMetaData(mmd.elementMetaData));
}
if (mmd.keyMetaData != null)
{
setKeyMetaData(new KeyMetaData(mmd.keyMetaData));
}
if (mmd.valueMetaData != null)
{
setValueMetaData(new ValueMetaData(mmd.valueMetaData));
}
if (mmd.orderMetaData != null)
{
setOrderMetaData(new OrderMetaData(mmd.orderMetaData));
}
if (mmd.indexMetaData != null)
{
setIndexMetaData(new IndexMetaData(mmd.indexMetaData));
}
if (mmd.uniqueMetaData != null)
{
setUniqueMetaData(new UniqueMetaData(mmd.uniqueMetaData));
}
if (mmd.foreignKeyMetaData != null)
{
setForeignKeyMetaData(new ForeignKeyMetaData(mmd.foreignKeyMetaData));
}
if (mmd.embeddedMetaData != null)
{
setEmbeddedMetaData(new EmbeddedMetaData(mmd.embeddedMetaData));
}
if (mmd.containerMetaData != null)
{
if (mmd.containerMetaData instanceof CollectionMetaData)
{
setContainer(new CollectionMetaData((CollectionMetaData)mmd.containerMetaData));
}
else if (mmd.containerMetaData instanceof MapMetaData)
{
setContainer(new MapMetaData((MapMetaData)mmd.containerMetaData));
}
else if (mmd.containerMetaData instanceof ArrayMetaData)
{
setContainer(new ArrayMetaData((ArrayMetaData)mmd.containerMetaData));
}
}
for (int i=0;i= 0)
{
// TODO Check if this is a valid className
this.className = name.substring(0,name.lastIndexOf('.'));
this.name = name.substring(name.lastIndexOf('.')+1);
}
else
{
this.name = name;
}
}
/**
* Method to provide the details of the field being represented by this MetaData hence populating
* certain parts of the MetaData. This is used to firstly provide defaults for attributes that aren't
* specified in the MetaData, and secondly to report any errors with attributes that have been specifed
* that are inconsistent with the field being represented.
* Either a field or a method should be passed in (one or the other) depending on what is being represented
* by this "member".
* @param clr ClassLoaderResolver to use for any class loading
* @param field Field that we are representing (if it's a field)
* @param method Method(property) that we are representing (if it's a method).
* @param primary the primary ClassLoader to use (or null)
* @param mmgr MetaData manager
*/
public synchronized void populate(ClassLoaderResolver clr, Field field, Method method, ClassLoader primary, MetaDataManager mmgr)
{
if (isPopulated() || isInitialised())
{
return;
}
if (mmgr != null)
{
// Set defaults for cascading when not yet set
ApiAdapter apiAdapter = mmgr.getNucleusContext().getApiAdapter();
if (cascadePersist == null)
{
cascadePersist = apiAdapter.getDefaultCascadePersistForField();
}
if (cascadeUpdate == null)
{
cascadeUpdate = apiAdapter.getDefaultCascadeUpdateForField();
}
if (cascadeDelete == null)
{
cascadeDelete = apiAdapter.getDefaultCascadeDeleteForField();
}
if (cascadeDetach == null)
{
cascadeDetach = false;
}
if (cascadeRefresh == null)
{
cascadeRefresh = apiAdapter.getDefaultCascadeRefreshForField();
}
}
if (field == null && method == null)
{
NucleusLogger.METADATA.error(Localiser.msg("044106", getClassName(), getName()));
throw new InvalidMemberMetaDataException("044106", getClassName(), getName());
}
// No class loader, so use System
if (clr == null)
{
NucleusLogger.METADATA.warn(Localiser.msg("044067",name,getClassName(true)));
clr = mmgr.getNucleusContext().getClassLoaderResolver(null);
}
memberRepresented = (field != null ? field : method);
if (type == null)
{
// Type not yet set so set from field/method (will only be set if we are imposing the type due to Java generics TypeVariable usage)
if (field != null)
{
this.type = field.getType();
}
else if (method != null)
{
this.type = method.getReturnType();
}
}
if (className != null)
{
// Property is overriding a superclass property, so check that it is valid
Class thisClass = null;
if (parent instanceof EmbeddedMetaData)
{
// is contained in a , , ,
// but could be multiple levels deep so adopt a generic strategy for finding the parent class
MetaData superMd = parent.getParent();
thisClass = ((AbstractMemberMetaData)superMd).getType();
}
else
{
// Overriding field in a superclass of this class
try
{
thisClass = clr.classForName(getAbstractClassMetaData().getPackageName() + "." + getAbstractClassMetaData().getName());
}
catch (ClassNotResolvedException cnre)
{
// Do nothing
}
}
Class fieldClass = null;
try
{
fieldClass = clr.classForName(className);
}
catch (ClassNotResolvedException cnre)
{
try
{
fieldClass = clr.classForName(getAbstractClassMetaData().getPackageName() + "." + className);
className = getAbstractClassMetaData().getPackageName() + "." + className;
}
catch (ClassNotResolvedException cnre2)
{
NucleusLogger.METADATA.error(Localiser.msg("044113", getClassName(), getName(), className));
NucleusException ne = new InvalidMemberMetaDataException("044113", getClassName(), getName(), className);
ne.setNestedException(cnre);
throw ne;
}
}
if (fieldClass != null && !fieldClass.isAssignableFrom(thisClass))
{
// TODO We could also check if persistable, but won't work when enhancing
NucleusLogger.METADATA.error(Localiser.msg("044114", getClassName(), getName(), className));
throw new InvalidMemberMetaDataException("044114", getClassName(), getName(), className);
}
}
if (primaryKey == null)
{
// Primary key not set by user so initialise it to false
primaryKey = Boolean.FALSE;
}
// Update "embedded" based on type
if (primaryKey == Boolean.FALSE && embedded == null)
{
Class element_type=getType();
if (element_type.isArray())
{
element_type = element_type.getComponentType();
if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(element_type))
{
embedded = Boolean.TRUE;
}
}
else if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(element_type))
{
embedded = Boolean.TRUE;
}
}
if (embedded == null)
{
embedded = Boolean.FALSE;
}
// Update "persistence-modifier" according to type etc
if (FieldPersistenceModifier.DEFAULT.equals(persistenceModifier))
{
boolean isPcClass = getType().isArray() ? isFieldArrayTypePersistable(mmgr) : mmgr.isFieldTypePersistable(type);
if (!isPcClass)
{
if (getType().isArray() && getType().getComponentType().isInterface())
{
isPcClass =
(mmgr.getMetaDataForClassInternal(getType().getComponentType(), clr) != null);
}
else if (getType().isInterface())
{
isPcClass = (mmgr.getMetaDataForClassInternal(getType(), clr) != null);
}
}
persistenceModifier = getDefaultFieldPersistenceModifier(getType(), memberRepresented.getModifiers(),
isPcClass, mmgr);
}
// TODO If this field is NONE in superclass, make it NONE here too
// Update "default-fetch-group" according to type
if (defaultFetchGroup == null && persistenceModifier.equals(FieldPersistenceModifier.NONE))
{
defaultFetchGroup = Boolean.FALSE;
}
else if (defaultFetchGroup == null && persistenceModifier.equals(FieldPersistenceModifier.TRANSACTIONAL))
{
defaultFetchGroup = Boolean.FALSE;
}
else if (defaultFetchGroup == null)
{
defaultFetchGroup = Boolean.FALSE;
if (!primaryKey.equals(Boolean.TRUE))
{
boolean foundGeneric = false;
TypeManager typeMgr = mmgr.getNucleusContext().getTypeManager();
if (Collection.class.isAssignableFrom(getType()))
{
String elementTypeName = null;
try
{
if (field != null)
{
elementTypeName = ClassUtils.getCollectionElementType(field);
}
else
{
elementTypeName = ClassUtils.getCollectionElementType(method);
}
}
catch (NucleusUserException nue)
{
// User has put some stupid type in so ignore it. Idiots
}
if (elementTypeName != null)
{
// Try to find using generic type specialisation
Class elementType = clr.classForName(elementTypeName);
if (typeMgr.isDefaultFetchGroupForCollection(getType(), elementType))
{
foundGeneric = true;
defaultFetchGroup = Boolean.TRUE;
}
}
}
if (!foundGeneric && typeMgr.isDefaultFetchGroup(getType()))
{
defaultFetchGroup = Boolean.TRUE;
}
}
}
// Field is not specified as "persistent" yet has DFG or primary-key !
if (persistenceModifier.equals(FieldPersistenceModifier.TRANSACTIONAL) ||
persistenceModifier.equals(FieldPersistenceModifier.NONE))
{
if (defaultFetchGroup == Boolean.TRUE || primaryKey == Boolean.TRUE)
{
throw new InvalidMemberMetaDataException("044109", getClassName(), name, this.getType().getName(), persistenceModifier.toString());
}
}
if (storeInLob)
{
// Set up the jdbcType/serialized settings according to the field type in line with JPA
boolean useClob = false;
if (type == String.class ||
(type.isArray() && type.getComponentType() == Character.class) || (type.isArray() && type.getComponentType() == char.class))
{
useClob = true;
if (columns == null || columns.size() == 0)
{
// Create a CLOB column. What if the RDBMS doesn't support CLOB ?
ColumnMetaData colmd = new ColumnMetaData();
colmd.setName(column);
colmd.setJdbcType("CLOB");
addColumn(colmd);
}
else
{
ColumnMetaData colmd = columns.get(0);
colmd.setJdbcType("CLOB");
}
}
if (!useClob)
{
serialized = Boolean.TRUE;
}
}
if (containerMetaData == null)
{
// No container information, so generate if array/collection/map field
if (type.isArray())
{
// User hasn't specified but the field is an array so infer it
Class arrayCls = type.getComponentType();
ArrayMetaData arrmd = new ArrayMetaData();
arrmd.setElementType(arrayCls.getName());
setContainer(arrmd);
}
else if (java.util.Collection.class.isAssignableFrom(type))
{
if (targetClassName != null)
{
// User has specified target class name (JPA) so generate the
CollectionMetaData collmd = new CollectionMetaData();
collmd.setElementType(targetClassName);
setContainer(collmd);
}
else
{
// No collection element type specified but using JDK1.5 so try generics
String elementType = null;
if (field != null)
{
elementType = ClassUtils.getCollectionElementType(field);
}
else
{
elementType = ClassUtils.getCollectionElementType(method);
}
if (elementType != null)
{
// Use generics information to infer any missing parts
CollectionMetaData collmd = new CollectionMetaData();
collmd.setElementType(elementType);
setContainer(collmd);
}
else
{
// Default to "Object" as element type
CollectionMetaData collmd = new CollectionMetaData();
collmd.setElementType(Object.class.getName());
setContainer(collmd);
NucleusLogger.METADATA.debug(Localiser.msg("044003", getClassName(), getName()));
}
}
}
else if (java.util.Map.class.isAssignableFrom(type))
{
if (targetClassName != null)
{
// User has specified target class name (JPA) so generate the