org.datanucleus.metadata.ClassMetaData Maven / Gradle / Ivy
Show all versions of datanucleus-core Show documentation
/**********************************************************************
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:
2004 Marco Schulze (NightLabs) - changed the behaviour to warn only if
an inherited class declares an own objectid and it equals the
one of the superclass.
2004 Andy Jefferson - Added discriminator/inheritance checks
2004 Erik Bengtson - changes for application identity
2004 Andy Jefferson - moved PK class checks out into JDOUtils
2007 Xuan Baldauf - little reduction in code duplication to anticipate changes regarding issue http://www.jpox.org/servlet/jira/browse/CORE-3272
...
**********************************************************************/
package org.datanucleus.metadata;
import java.lang.reflect.Field;
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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.api.ApiAdapter;
import org.datanucleus.exceptions.ClassNotResolvedException;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.identity.IdentityUtils;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
/**
* Representation of the MetaData of a class.
* Extends the abstract definition to include implementations, fields, embedded-only tags.
* Has a parent PackageMetaData that can contain the metadata for several classes.
*
* Lifecycle state
* This object supports 3 lifecycle states. The first is the raw constructed object which represents pure MetaData (maybe from a MetaData file).
* The second is a "populated" object which represents MetaData for a Class with the metadata aligned to be appropriate for that Class.
* The third is "initialised" once the internal arrays are created.
* This object, once populated, will represent ALL fields in the class (including static, final and transient fields).
*
* Fields/Properties
* This object keeps a list of FieldMetaData/PropertyMetaData objects for the fields of this class.
* In addition it has an array of FieldMetaData objects representing those that are actually managed by JDO ("managedFields").
* This second set does not contain things like static, final or transient fields since JDO doesn't support those yet.
* Fields are of 2 types. The first are normal fields of this class.
* These have their own "relative" field number, relative to this class.
* The second type are "overriding" fields which override the baseline field in a superclass. These fields have no "relative" field number since
* they are relative to this class (and such a relative field number would make no sense).
* Fields are all added through addField() during the parse process, and are updated during the populate/initialise process to define their
* relative field numbers. Please refer to FieldMetaData for more details of fields.
*
*
Numbering of fields
* Fields of the class are numbered in 2 ways. The first way is the numbering within a class.
* In a class, the field 'id's will start at 0. If a class is inherited, it will also have a second numbering for its fields - the
* "absolute" numbering. With "absolute" numbering, the fields start at the first field in the root superclass which has absolute number 0, and they are
* numbered from there, navigating down the hierarchy. In terms of what is stored in the records, the FieldMetaData stores fieldId as the first
* method (relative to the class it is in). The "absolute" numbering is always derived from this and the inheritance hierarchy.
*/
public class ClassMetaData extends AbstractClassMetaData
{
private static final long serialVersionUID = -1029032058753152022L;
/** List of implements. */
protected List implementations = null;
/** Is the persistable class abstract. */
protected boolean isAbstract;
/**
* Constructor.
* Takes the basic string information found in the MetaData file.
* @param parent The package to which this class belongs
* @param name Name of class
*/
public ClassMetaData(final PackageMetaData parent, final String name)
{
super(parent, name);
}
/**
* Constructor for creating the ClassMetaData for an implementation of a "persistent-interface".
* @param imd MetaData for the "persistent-interface"
* @param implClassName Name of the implementation class
* @param copyFields Whether to copy the fields of the interface too
*/
public ClassMetaData(final InterfaceMetaData imd, String implClassName, boolean copyFields)
{
super(imd, implClassName, copyFields);
}
/**
* Constructor for creating the ClassMetaData for an implementation of a "persistent-abstract-class".
* @param cmd MetaData for the implementation of the "persistent-abstract-class"
* @param implClassName Name of the implementation class
*/
public ClassMetaData(final ClassMetaData cmd, String implClassName)
{
super(cmd, implClassName);
}
/**
* Method to provide the details of the class being represented by this MetaData.
* This can be 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 specified that are inconsistent with the
* class being represented.
*
* One possible use of this method would be to take a basic ClassMetaData for a class and call this, passing in the users class.
* This would then add AbstractMemberMetaData for all fields in this class providing defaults for all of these.
* @param clr ClassLoaderResolver to use in loading any classes
* @param primary the primary ClassLoader to use (or null)
* @param mgr MetaData manager
*/
public synchronized void populate(ClassLoaderResolver clr, ClassLoader primary, MetaDataManager mgr)
{
if (isInitialised() || isPopulated())
{
NucleusLogger.METADATA.error(Localiser.msg("044068", name));
throw new NucleusException(Localiser.msg("044068", fullName)).setFatal();
}
if (populating)
{
return;
}
this.mmgr = mgr;
try
{
if (NucleusLogger.METADATA.isDebugEnabled())
{
NucleusLogger.METADATA.debug(Localiser.msg("044075", fullName));
}
populating = true;
Class cls = loadClass(clr, primary);
isAbstract = Modifier.isAbstract(cls.getModifiers());
// Load any Annotations definition for this class
if (!isMetaDataComplete())
{
mmgr.addAnnotationsDataToClass(cls, this, clr);
}
// Load any ORM definition for this class
mmgr.addORMDataToClass(cls, clr);
// If a class is an inner class and is non-static it is invalid
if (ClassUtils.isInnerClass(fullName) && !Modifier.isStatic(cls.getModifiers()) && persistenceModifier == ClassPersistenceModifier.PERSISTENCE_CAPABLE)
{
throw new InvalidClassMetaDataException("044063", fullName);
}
if (entityName == null)
{
// No entity name given so just default to the name of the class (without package)
this.entityName = name;
}
determineSuperClassName(clr, cls);
inheritIdentity();
determineIdentity();
validateUserInputForIdentity();
addMetaDataForMembersNotInMetaData(cls);
// Set inheritance
validateUserInputForInheritanceMetaData(isAbstract());
determineInheritanceMetaData();
applyDefaultDiscriminatorValueWhenNotSpecified();
// Process all members marked as UNKNOWN (i.e override from JPA) and eliminate clashes with any generic overrides from addMetaDataForMembersNotInMetaData(...)
Set membersToDelete = null;
for (AbstractMemberMetaData mmd : members)
{
if (mmd.className != null && mmd.className.equals("#UNKNOWN"))
{
// Field is for a superclass but we didn't know which at creation so resolve it
if (pcSuperclassMetaData == null)
{
// No superclass so it doesn't make sense so assume to be for this class
mmd.className = null;
}
else
{
AbstractMemberMetaData superFmd = pcSuperclassMetaData.getMetaDataForMember(mmd.getName());
if (superFmd != null)
{
// Field is for a superclass so set its "className"
mmd.className = (superFmd.className != null) ? superFmd.className : superFmd.getClassName();
// Copy across other attributes of the original definition
mmd.primaryKey = superFmd.primaryKey;
mmd.persistenceModifier = superFmd.persistenceModifier;
mmd.valueStrategy = superFmd.valueStrategy;
mmd.valueGeneratorName = superFmd.valueGeneratorName;
mmd.sequence = superFmd.sequence;
mmd.cacheable = superFmd.cacheable;
mmd.storeInLob = superFmd.storeInLob;
// TODO Copy across more attributes
for (AbstractMemberMetaData existingMmd : members)
{
if (existingMmd.getName().equals(mmd.getName()) && existingMmd != mmd)
{
mmd.type = existingMmd.getType();
if (membersToDelete == null)
{
membersToDelete = new HashSet<>();
}
membersToDelete.add(existingMmd);
break;
}
}
}
}
}
}
if (membersToDelete != null)
{
members.removeAll(membersToDelete);
}
if (objectidClass == null)
{
// No user-defined objectid-class but potentially have SingleFieldIdentity so make sure PK fields are set
populateMemberMetaData(clr, cls, true, primary); // PK fields
determineObjectIdClass();
populateMemberMetaData(clr, cls, false, primary); // Non-PK fields
}
else
{
populateMemberMetaData(clr, cls, true, primary);
populateMemberMetaData(clr, cls, false, primary);
determineObjectIdClass();
}
validateUnmappedColumns();
// populate the implements
if (implementations != null)
{
for (ImplementsMetaData implmd : implementations)
{
implmd.populate(clr, primary);
}
}
if (persistentInterfaceImplNeedingTableFromSuperclass)
{
// Need to go up to next superinterface and make sure its metadata is populated
// until we find the next interface with metadata with inheritance strategy of "new-table".
AbstractClassMetaData acmd = getMetaDataForSuperinterfaceManagingTable(cls, clr);
if (acmd != null)
{
table = acmd.table;
schema = acmd.schema;
catalog = acmd.catalog;
}
persistentInterfaceImplNeedingTableFromSuperclass = false;
}
else if (persistentInterfaceImplNeedingTableFromSubclass)
{
// TODO Cater for finding the subclass-table that manages our table
persistentInterfaceImplNeedingTableFromSubclass = false;
}
setPopulated();
}
catch (RuntimeException e)
{
NucleusLogger.METADATA.debug(e);
throw e;
}
finally
{
populating = false;
}
}
/**
* Method to find a superinterface with MetaData that specifies NEW_TABLE inheritance strategy
* @param cls The class
* @param clr ClassLoader resolver
* @return The AbstractClassMetaData for the class managing the table
*/
private AbstractClassMetaData getMetaDataForSuperinterfaceManagingTable(Class cls, ClassLoaderResolver clr)
{
for (Class> superintf : ClassUtils.getSuperinterfaces(cls))
{
AbstractClassMetaData acmd = mmgr.getMetaDataForInterface(superintf, clr);
if (acmd != null && acmd.getInheritanceMetaData() != null)
{
if (acmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.NEW_TABLE)
{
// Found it
return acmd;
}
else if (acmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUPERCLASS_TABLE)
{
// Try further up the hierarchy
return getMetaDataForSuperinterfaceManagingTable(superintf, clr);
}
}
}
return null;
}
/**
* Add MetaData of fields/properties not declared in MetaData.
* Note that if a member is defined using some generic type in the superclass and this class can use a TypeVariable to resolve it then this
* will add the member to "members" here since the type will be different to this class.
* @param cls Class represented by this metadata
*/
protected void addMetaDataForMembersNotInMetaData(Class cls)
{
// Access API since we treat things differently for JPA/Jakarta and JDO
ApiAdapter apiAdapter = mmgr.getNucleusContext().getApiAdapter();
Set memberNames = new HashSet<>();
for (AbstractMemberMetaData mmd : members)
{
memberNames.add(mmd.getName());
}
// Add fields/properties for the class that don't have MetaData, using Reflection.
// NOTE 1 : We ignore fields/properties in superclasses
// NOTE 2 : We ignore "enhanced" fields/properties (added by the enhancer)
// NOTE 3 : We ignore inner class fields/properties (containing "$")
// NOTE 4 : We sort the fields/properties into ascending alphabetical order
Collections.sort(members);
try
{
// check if we have any persistent properties in this class
boolean hasProperties = false;
for (int i=0; i j && paramTypeArgs[j] instanceof Class)
{
// Declared type is fully defined (rather than just bound)
NucleusLogger.METADATA.debug("Class=" + cls.getName() + " property=" + propertyName +
" declared to return " + methodTypeVar + ", namely TypeVariable(" + j + ") of " + declCls.getName() + " so using " + paramTypeArgs[j]);
if (!memberNames.contains(propertyName))
{
// No property of this name - add a default PropertyMetaData for this method with the type set to what we need
NucleusLogger.METADATA.debug(Localiser.msg("044060", fullName, propertyNameFull));
AbstractMemberMetaData overriddenMmd = getMemberBeingOverridden(propertyName);
AbstractMemberMetaData mmd = new PropertyMetaData(this, propertyNameFull);
mergeMemberMetaDataForOverrideOfType((Class) paramTypeArgs[j], mmd, overriddenMmd);
members.add(mmd);
memberNames.add(mmd.getName());
Collections.sort(members);
}
else
{
// User has overridden the field, so update the type on their definition
AbstractMemberMetaData overrideMmd = getMetaDataForMember(propertyName);
overrideMmd.type = (Class) paramTypeArgs[j];
}
foundTypeForTypeVariable = true;
break;
}
}
}
}
if (!foundTypeForTypeVariable)
{
// Search bounds of this class for the property type variable (e.g "MyClass extends MySuperClass" will give bound of BaseD)
if (clsDeclTypes != null)
{
for (int j=0;j" so take SomeType
boolean updateType = true;
AbstractMemberMetaData overriddenMmd = getMetaDataForMember(propertyName);
if (overriddenMmd != null)
{
if (overriddenMmd.getTypeName().equals(((Class)boundTypes[0]).getName()))
{
// Already overridden the type in a superclass, so ignore
updateType = false;
}
}
if (updateType)
{
NucleusLogger.METADATA.debug("Class=" + cls.getName() + " property=" + propertyName +
" declared to return " + methodTypeVar + ", namely TypeVariable(" + j + ") with bound, so using bound of " + boundTypes[0]);
if (!memberNames.contains(propertyName))
{
// No property of this name - add a default PropertyMetaData for this method with the type set to what we need
NucleusLogger.METADATA.debug(Localiser.msg("044060", fullName, propertyNameFull));
AbstractMemberMetaData mmd = new PropertyMetaData(this, propertyNameFull);
mergeMemberMetaDataForOverrideOfType((Class)boundTypes[0], mmd, overriddenMmd);
members.add(mmd);
memberNames.add(mmd.getName());
Collections.sort(members);
}
else
{
// User has overridden the field, so update the type on their definition
AbstractMemberMetaData overrideMmd = getMetaDataForMember(propertyName);
overrideMmd.type = (Class) boundTypes[0];
}
}
foundTypeForTypeVariable = true;
break;
}
}
}
}
}
}
}
}
else
{
// FIELDS : Check for any TypeVariables used with fields in superclass(es) and override the metadata in the superclass to use the right type
Class theClass = cls;
while (theClass.getSuperclass() != null)
{
theClass = theClass.getSuperclass();
Field[] theclsFields = theClass.getDeclaredFields();
for (int i=0;i j && paramTypeArgs[j] instanceof Class)
{
// Declared type is fully defined (rather than just bound)
NucleusLogger.METADATA.debug("Class=" + cls.getName() + " field=" + fieldName +
" declared to be " + fieldTypeVar + ", namely TypeVariable(" + j + ") of " + declCls.getName() + " so using " + paramTypeArgs[j]);
if (!memberNames.contains(fieldName))
{
// No member of this name - add a default FieldMetaData for this field with the type set to what we need
NucleusLogger.METADATA.debug(Localiser.msg("044060", fullName, fieldNameFull));
AbstractMemberMetaData overriddenMmd = getMemberBeingOverridden(fieldName);
// Merge the overridden member with the limited info specified in this override
AbstractMemberMetaData mmd = new FieldMetaData(this, fieldNameFull);
// Note that if we override a single PK field we will have objectIdClass=ObjectId in the generics superclass, and still ObjectId here
// We have to keep to continue like this since the superclass will have been enhanced to have ObjectId in its bytecode contract.
mergeMemberMetaDataForOverrideOfType((Class) paramTypeArgs[j], mmd, overriddenMmd);
members.add(mmd);
memberNames.add(mmd.getName());
Collections.sort(members);
}
else
{
// User has overridden the field, so update the type on their definition
AbstractMemberMetaData overrideMmd = getMetaDataForMember(fieldName);
overrideMmd.type = (Class) paramTypeArgs[j];
}
foundTypeForTypeVariable = true;
break;
}
}
}
}
if (!foundTypeForTypeVariable)
{
// Search bounds of this class for the field type variable (e.g "MyClass extends MySuperClass" will give bound of BaseD)
if (clsDeclTypes != null)
{
for (int j=0;j" so take SomeType
boolean updateType = true;
AbstractMemberMetaData overriddenMmd = getMetaDataForMember(fieldName);
if (overriddenMmd != null)
{
if (overriddenMmd.getTypeName().equals(((Class)boundTypes[0]).getName()))
{
// Already defined the type in a superclass, with same type as this bound so ignore
updateType = false;
}
}
if (updateType)
{
NucleusLogger.METADATA.debug("Class=" + cls.getName() + " field=" + fieldName +
" declared to be " + fieldTypeVar + ", namely TypeVariable(" + j + ") with bound, so using bound of " + boundTypes[0]);
if (!memberNames.contains(fieldName))
{
// Field defined as generic but not found a meta-data definition, so use boundTypes to add override meta-data with the correct type
NucleusLogger.METADATA.debug(Localiser.msg("044060", fullName, fieldNameFull));
AbstractMemberMetaData mmd = new FieldMetaData(this, fieldNameFull);
mergeMemberMetaDataForOverrideOfType((Class)boundTypes[0], mmd, overriddenMmd);
members.add(mmd);
memberNames.add(mmd.getName());
Collections.sort(members);
}
else
{
// User has overridden the field, so update the type on their definition
AbstractMemberMetaData overrideMmd = getMetaDataForMember(fieldName);
overrideMmd.type = (Class) boundTypes[0];
}
}
foundTypeForTypeVariable = true;
break;
}
}
}
}
}
}
}
}
}
}
catch (Exception e)
{
NucleusLogger.METADATA.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage());
}
}
/**
* Method to merge in an overridden member details into the overriding meta-data, updating the type.
* If the overriddenMmd is null then simply updates the type on the mmd.
* @param type The type to use
* @param mmd The overriding member meta-data
* @param overriddenMmd The (base) overridden meta-data
*/
private void mergeMemberMetaDataForOverrideOfType(Class type, AbstractMemberMetaData mmd, AbstractMemberMetaData overriddenMmd)
{
// TODO Use MetaDataMerger to merge in everything else specified in the member
mmd.type = type;
if (overriddenMmd != null)
{
mmd.primaryKey = overriddenMmd.primaryKey;
mmd.embedded = overriddenMmd.embedded;
mmd.serialized = overriddenMmd.serialized;
mmd.persistenceModifier = overriddenMmd.persistenceModifier;
mmd.valueStrategy = overriddenMmd.valueStrategy;
}
}
/**
* Populate MetaData for all members.
* @param clr The ClassLoaderResolver
* @param cls This class
* @param pkMembers Process pk fields/properties (or non-PK if false)
* @param primary the primary ClassLoader to use (or null)
* @throws InvalidMetaDataException if the Class for a declared type in a field cannot be loaded by the clr
* @throws InvalidMetaDataException if a field declared in the MetaData does not exist in the Class
*/
protected void populateMemberMetaData(ClassLoaderResolver clr, Class cls, boolean pkMembers, ClassLoader primary)
{
Collections.sort(members);
// Populate the real field values. This will populate any containers in these members also
for (AbstractMemberMetaData mmd : members)
{
if (pkMembers == mmd.isPrimaryKey())
{
Class fieldCls = cls;
if (!mmd.fieldBelongsToClass())
{
// Field overrides a field in a superclass, so find the class
try
{
fieldCls = clr.classForName(mmd.getClassName());
}
catch (ClassNotResolvedException cnre)
{
// Not found at specified location, so try the same package as this class
String fieldClassName = getPackageName() + "." + mmd.getClassName();
try
{
fieldCls = clr.classForName(fieldClassName);
mmd.setClassName(fieldClassName);
}
catch (ClassNotResolvedException cnre2)
{
NucleusLogger.METADATA.error(Localiser.msg("044092", fullName, mmd.getFullFieldName(), fieldClassName));
throw new InvalidClassMetaDataException("044092", fullName, mmd.getFullFieldName(), fieldClassName);
}
}
}
boolean populated = false;
if (mmd instanceof PropertyMetaData)
{
// User class must have a getter and setter for this property as per Java Beans
Method getMethod = null;
try
{
// Find the getter
// a). Try as a standard form of getter (getXXX)
getMethod = fieldCls.getDeclaredMethod(ClassUtils.getJavaBeanGetterName(mmd.getName(), false)); // Only public?
}
catch (Exception e)
{
try
{
// b). Try as a boolean form of getter (isXXX)
getMethod = fieldCls.getDeclaredMethod(ClassUtils.getJavaBeanGetterName(mmd.getName(), true)); // Only public?
}
catch (Exception e2)
{
}
}
if (getMethod != null && getMethod.getReturnType() == void.class)
{
throw new InvalidClassMetaDataException("044166", fullName, mmd.getName());
}
if (getMethod == null && mmd.getPersistenceModifier() != FieldPersistenceModifier.NONE)
{
// Property is persistent yet no getter!
throw new InvalidClassMetaDataException("044073", fullName, mmd.getName());
}
Method setMethod = null;
try
{
// Find the setter
String setterName = ClassUtils.getJavaBeanSetterName(mmd.getName());
Method[] methods = fieldCls.getMethods(); // Only gives public methods
for (int i=0;i();
for (AbstractMemberMetaData mmd : members)
{
if (mmd.isFieldToBePersisted())
{
if (mmd.fieldBelongsToClass())
{
// Definition of a member in this class
mmd.setFieldId(memberId);
managedMembers[memberId] = mmd;
memberPositionsByName.put(mmd.getName(), Integer.valueOf(memberId));
memberId++;
}
else
{
// Definition of override of a member in a superclass
overriddenMembers[overriddenMemberId++] = mmd;
if (pcSuperclassMetaData == null)
{
// User specified override yet no superclass!
throw new InvalidClassMetaDataException("044162", fullName, mmd.getFullFieldName());
}
AbstractMemberMetaData superMmd = pcSuperclassMetaData.getMemberBeingOverridden(mmd.getName());
if (superMmd != null)
{
// Merge in any additional info not specified in the overridden field TODO Use MetaDataMerger to merge in better than this
if (superMmd.isPrimaryKey())
{
mmd.setPrimaryKey(true);
}
}
else
{
// TODO Catch this, illegal override
}
}
}
}
if (pcSuperclassMetaData != null)
{
if (!pcSuperclassMetaData.isInitialised())
{
pcSuperclassMetaData.initialise(clr);
}
noOfInheritedManagedMembers = pcSuperclassMetaData.getNoOfInheritedManagedMembers() + pcSuperclassMetaData.getNoOfManagedMembers();
}
// Set up the various convenience arrays of field numbers
initialiseMemberPositionInformation();
// Initialise any sub-objects
if (implementations != null)
{
for (ImplementsMetaData implmd : implementations)
{
implmd.initialise(clr);
}
}
if (joins != null)
{
for (JoinMetaData joinmd : joins)
{
joinmd.initialise(clr);
}
}
if (foreignKeys != null)
{
for (ForeignKeyMetaData fkmd : foreignKeys)
{
fkmd.initialise(clr);
}
}
if (indexes != null)
{
for (IndexMetaData idxmd : indexes)
{
idxmd.initialise(clr);
}
}
if (uniqueConstraints != null)
{
for (UniqueMetaData unimd : uniqueConstraints)
{
unimd.initialise(clr);
}
}
if (fetchGroups != null)
{
fetchGroupMetaDataByName = new HashMap<>();
for (FetchGroupMetaData fgmd : fetchGroups)
{
fgmd.initialise(clr);
fetchGroupMetaDataByName.put(fgmd.getName(), fgmd);
}
}
// If using datastore id and user hasn't provided the identity element,
// add a defaulted one (using the superclass if available)
if (identityType == IdentityType.DATASTORE && datastoreIdentityMetaData == null)
{
if (pcSuperclassMetaData != null)
{
DatastoreIdentityMetaData superImd = pcSuperclassMetaData.getDatastoreIdentityMetaData();
datastoreIdentityMetaData = new DatastoreIdentityMetaData();
datastoreIdentityMetaData.setColumnName(superImd.getColumnName());
datastoreIdentityMetaData.setValueStrategy(superImd.getValueStrategy());
datastoreIdentityMetaData.setSequence(superImd.getSequence());
datastoreIdentityMetaData.parent = this;
}
else
{
datastoreIdentityMetaData = new DatastoreIdentityMetaData();
datastoreIdentityMetaData.parent = this;
}
}
if (primaryKeyMetaData != null)
{
primaryKeyMetaData.initialise(clr);
}
if (versionMetaData != null)
{
versionMetaData.initialise(clr);
}
if (datastoreIdentityMetaData != null)
{
datastoreIdentityMetaData.initialise(clr);
}
if (inheritanceMetaData != null)
{
inheritanceMetaData.initialise(clr);
}
if (multitenancyMetaData != null)
{
multitenancyMetaData.initialise(clr);
}
if (softDeleteMetaData != null)
{
softDeleteMetaData.initialise(clr);
}
if (identityType == IdentityType.APPLICATION)
{
usesSingleFieldIdentityClass = IdentityUtils.isSingleFieldIdentityClass(getObjectidClass());
}
setInitialised();
}
finally
{
initialising = false;
mmgr.abstractClassMetaDataInitialised(this);
}
}
/**
* Whether the persistable class is abstract.
* @return true if the persistable class is abstract
*/
public boolean isAbstract()
{
return isAbstract;
}
/**
* Utility to add a defaulted FieldMetaData to the class. Provided as a method since then any derived
* classes can override it (e.g ClassMetaData can create a FieldMetaData)
* @param name name of field
* @return the new FieldMetaData
*/
protected AbstractMemberMetaData newDefaultedProperty(String name)
{
return new FieldMetaData(this, name);
}
/**
* Accessor for the implements MetaData
* @return Returns the implements MetaData.
*/
public final List getImplementsMetaData()
{
return implementations;
}
/**
* Method to add an implements to this class.
* @param implmd Meta-Data for the implements
*/
public void addImplements(ImplementsMetaData implmd)
{
if (implmd == null)
{
return;
}
if (isInitialised())
{
throw new RuntimeException("Already initialised");
}
if (implementations == null)
{
implementations = new ArrayList<>();
}
implementations.add(implmd);
implmd.parent = this;
}
public String toString()
{
StringBuilder str = new StringBuilder(super.toString()).append(" [").append(this.getFullClassName()).append("]");
if (identityType != null)
{
str.append(" identity=").append(identityType.toString());
if (identityType == IdentityType.APPLICATION)
{
str.append("(").append(getNoOfPrimaryKeyMembers()).append(" pkFields, id=").append(objectidClass).append(")");
}
}
str.append(", modifier=" + persistenceModifier);
str.append(", embeddedOnly=" + embeddedOnly);
if (inheritanceMetaData != null && inheritanceMetaData.getStrategy() != null)
{
str.append(", inheritance=").append(inheritanceMetaData.getStrategy().toString());
}
if (isInitialised())
{
str.append(", managedMembers.size=").append(managedMembers.length);
str.append(", overriddenMembers.size=").append(overriddenMembers.length);
str.append("\n");
str.append(" managed=[");
for (int i=0;i