blob: 0a4bc5b7a77f28c08b07297219b6b65675e0794b [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 05/16/2008-1.0M8 Guy Pelletier
// - 218084: Implement metadata merging functionality between mapping files
// 05/23/2008-1.0M8 Guy Pelletier
// - 211330: Add attributes-complete support to the EclipseLink-ORM.XML Schema
// 05/30/2008-1.0M8 Guy Pelletier
// - 230213: ValidationException when mapping to attribute in MappedSuperClass
// 06/20/2008-1.0M9 Guy Pelletier
// - 232975: Failure when attribute type is generic
// 07/15/2008-1.0.1 Guy Pelletier
// - 240679: MappedSuperclass Id not picked when on get() method accessor
// 09/23/2008-1.1 Guy Pelletier
// - 241651: JPA 2.0 Access Type support
// 10/01/2008-1.1 Guy Pelletier
// - 249329: To remain JPA 1.0 compliant, any new JPA 2.0 annotations should be referenced by name
// 12/12/2008-1.1 Guy Pelletier
// - 249860: Implement table per class inheritance support.
// 01/28/2009-2.0 Guy Pelletier
// - 248293: JPA 2.0 Element Collections (part 1)
// 02/06/2009-2.0 Guy Pelletier
// - 248293: JPA 2.0 Element Collections (part 2)
// 02/25/2009-2.0 Guy Pelletier
// - 265359: JPA 2.0 Element Collections - Metadata processing portions
// 03/27/2009-2.0 Guy Pelletier
// - 241413: JPA 2.0 Add EclipseLink support for Map type attributes
// 04/24/2009-2.0 Guy Pelletier
// - 270011: JPA 2.0 MappedById support
// 06/02/2009-2.0 Guy Pelletier
// - 278768: JPA 2.0 Association Override Join Table
// 06/16/2009-2.0 Guy Pelletier
// - 277039: JPA 2.0 Cache Usage Settings
// 06/25/2009-2.0 Michael O'Brien
// - 266912: add isMappedSuperclass() helper function in support
// of MappedSuperclass handling for the Metamodel API.
// 08/11/2009-2.0 Michael O'Brien
// - 284147: So we do not add a pseudo PK Field for MappedSuperclasses when
// 1 or more PK fields already exist on the descriptor.
// Add m_idAccessor map and hasIdAccessor() function.
// 10/21/2009-2.0 Guy Pelletier
// - 290567: mappedbyid support incomplete
// 01/05/2010-2.1 Guy Pelletier
// - 211324: Add additional event(s) support to the EclipseLink-ORM.XML Schema
// 01/22/2010-2.0.1 Guy Pelletier
// - 294361: incorrect generated table for element collection attribute overrides
// 03/08/2010-2.1 Michael O'Brien
// - 300051: JPA 2.0 Metamodel processing requires EmbeddedId validation moved higher from
// EmbeddedIdAccessor.process() to MetadataDescriptor.addAccessor() so we
// can better determine when to add the MAPPED_SUPERCLASS_RESERVED_PK_NAME
// temporary PK field used to process MappedSuperclasses for the Metamodel API
// during MetadataProject.addMetamodelMappedSuperclass()
// 04/09/2010-2.1 Guy Pelletier
// - 307050: Add defaults for access methods of a VIRTUAL access type
// 05/03/2009-1.2.1 Guy Pelletier
// - 307547: Exception in order by clause after migrating to eclipselink 1.2 release
// 06/01/2010-2.1 Guy Pelletier
// - 315195: Add new property to avoid reading XML during the canonical model generation
// 06/14/2010-2.2 Guy Pelletier
// - 264417: Table generation is incorrect for JoinTables in AssociationOverrides
// 06/18/2010-2.2 Guy Pelletier
// - 300458: EclispeLink should throw a more specific exception than NPE
// 07/16/2010-2.2 Guy Pelletier
// - 260296: mixed access with no Transient annotation does not result in error
// 08/04/2010-2.1.1 Guy Pelletier
// - 315782: JPA2 derived identity metadata processing validation doesn't account for autoboxing
// 08/11/2010-2.2 Guy Pelletier
// - 312123: JPA: Validation error during Id processing on parameterized generic OneToOne Entity relationship from MappedSuperclass
// 09/03/2010-2.2 Guy Pelletier
// - 317286: DB column lenght not in sync between @Column and @JoinColumn
// 10/15/2010-2.2 Guy Pelletier
// - 322008: Improve usability of additional criteria applied to queries at the session/EM
// 10/27/2010-2.2 Guy Pelletier
// - 328114: @AttributeOverride does not work with nested embeddables having attributes of the same name
// 12/01/2010-2.2 Guy Pelletier
// - 331234: xml-mapping-metadata-complete overriden by metadata-complete specification
// 12/02/2010-2.2 Guy Pelletier
// - 251554: ExcludeDefaultMapping annotation needed
// 03/24/2011-2.3 Guy Pelletier
// - 337323: Multi-tenant with shared schema support (part 1)
// 04/01/2011-2.3 Guy Pelletier
// - 337323: Multi-tenant with shared schema support (part 2)
// 09/09/2011-2.3.1 Guy Pelletier
// - 356197: Add new VPD type to MultitenantType
// 11/10/2011-2.4 Guy Pelletier
// - 357474: Address primaryKey option from tenant discriminator column
// 30/05/2012-2.4 Guy Pelletier
// - 354678: Temp classloader is still being used during metadata processing
// 04/07/2012-2.5 Guy Pelletier
// - 384275: Customizer from a mapped superclass is not overridden by an entity customizer
// 10/09/2012-2.5 Guy Pelletier
// - 374688: JPA 2.1 Converter support
// 11/28/2012-2.5 Guy Pelletier
// - 374688: JPA 2.1 Converter support
// 05/19/2014-2.6 Tomas Kraus
// - 437578: @Cacheable annotation value is now passed to CachePolicy
// 09/02/2019-3.0 Alexandre Jacob
// - 527415: Fix code when locale is tr, az or lt
package org.eclipse.persistence.internal.jpa.metadata;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_ACCESS_FIELD;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_ACCESS_PROPERTY;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.eclipse.persistence.annotations.ExistenceType;
import org.eclipse.persistence.config.CacheIsolationType;
import org.eclipse.persistence.descriptors.CMPPolicy;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorEventListener;
import org.eclipse.persistence.descriptors.RelationalDescriptor;
import org.eclipse.persistence.descriptors.ReturningPolicy;
import org.eclipse.persistence.descriptors.SingleTableMultitenantPolicy;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy;
import org.eclipse.persistence.internal.descriptors.VirtualAttributeMethodInfo;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.jpa.CMP3Policy;
import org.eclipse.persistence.internal.jpa.metadata.accessors.MetadataAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.PropertyMetadata;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EmbeddableAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.EmbeddedIdAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.IdAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.MappedKeyMapAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.MappingAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataClass;
import org.eclipse.persistence.internal.jpa.metadata.columns.AssociationOverrideMetadata;
import org.eclipse.persistence.internal.jpa.metadata.columns.AttributeOverrideMetadata;
import org.eclipse.persistence.internal.jpa.metadata.columns.TenantDiscriminatorColumnMetadata;
import org.eclipse.persistence.internal.jpa.metadata.converters.ConvertMetadata;
import org.eclipse.persistence.internal.jpa.metadata.listeners.EntityListener;
import org.eclipse.persistence.internal.jpa.metadata.mappings.AccessMethodsMetadata;
import org.eclipse.persistence.mappings.DatabaseMapping;
/**
* INTERNAL:
* Common metatata descriptor for the annotation and xml processors. This class
* is a wrap on an actual EclipseLink descriptor.
*
* @author Guy Pelletier
* @since TopLink EJB 3.0 Reference Implementation
*/
public class MetadataDescriptor {
private boolean m_isCascadePersist;
private boolean m_hasCache;
private boolean m_hasCacheInterceptor;
private boolean m_hasDefaultRedirectors;
private boolean m_hasChangeTracking;
private boolean m_hasCustomizer;
private boolean m_hasReadOnly;
private boolean m_hasCopyPolicy;
private boolean m_hasPrimaryKey;
private boolean m_hasSerializedObjectPolicy;
// Default access methods are used for VIRTUAL mapping attributes when
// the attributes do not specify their own access methods.
private AccessMethodsMetadata m_defaultAccessMethods;
/**
* Entity @Cacheable annotation value (cacheable value of this descriptor).
* This value contains Boolean value equal to annotation value or null when
* no annotation was set for entity. Parent values are ignored, value refers
* to current class only.
*/
private Boolean m_cacheable;
private Boolean m_usesCascadedOptimisticLocking;
private ClassAccessor m_classAccessor;
private DatabaseTable m_primaryTable;
// The embedded id accessor for this descriptor if one exists.
private EmbeddedIdAccessor m_embeddedIdAccessor;
private List<String> m_idAttributeNames;
private List<String> m_orderByAttributeNames;
private List<String> m_idOrderByAttributeNames;
private List<MetadataDescriptor> m_embeddableDescriptors;
private List<TenantDiscriminatorColumnMetadata> m_defaultTenantDiscriminatorColumns;
// Holds a list of derived id accessors.
private List<ObjectAccessor> m_derivedIdAccessors;
private Map<String, String> m_pkClassIDs;
private Map<String, String> m_genericTypes;
private Map<String, IdAccessor> m_idAccessors;
// Holds all fields from BasicAccessors (Basic, Id, Version, Transformation)
private Map<String, DatabaseField> m_fields;
private Map<String, MappingAccessor> m_mappingAccessors;
private Map<DatabaseField, MappingAccessor> m_primaryKeyAccessors;
private Map<String, PropertyMetadata> m_properties;
private Map<DatabaseField, DatabaseField> m_pkJoinColumnAssociations;
private Map<String, AttributeOverrideMetadata> m_attributeOverrides;
private Map<String, AssociationOverrideMetadata> m_associationOverrides;
private Map<String, Map<String, MetadataAccessor>> m_biDirectionalManyToManyAccessors;
private Map<String, List<ConvertMetadata>> m_converts;
private Map<String, List<ConvertMetadata>> m_mapKeyConverts;
private MetadataClass m_pkClass;
private MetadataClass m_javaClass;
// This is the root descriptor of the inheritance hierarchy. That is, for
// the entity that defines the inheritance strategy.
private MetadataDescriptor m_inheritanceRootDescriptor;
// This is our immediate parent's descriptor. Which may also be the root.
private MetadataDescriptor m_inheritanceParentDescriptor;
// Used only for a mapped superclass descriptor. Allows us to look up
// more specific types when a mapping may use a generic specification.
// Note: a mapped superclass can not be discovered without the help of
// an entity accessor. Therefore, if this descriptor is to a mapped super
// class, the child entity accessor will (and must) be set.
private MetadataDescriptor m_metamodelMappedSuperclassChildDescriptor;
private ClassDescriptor m_descriptor;
// This is the default access type for the class accessor of this
// descriptor. The default access type is needed for those embeddables and
// mapped superclasses that are 'owned' or rely on this value for their own
// processing. It does not reflect an explicit access type.
private String m_defaultAccess;
private String m_defaultSchema;
private String m_defaultCatalog;
private String m_existenceChecking;
/**
* INTERNAL:
*/
public MetadataDescriptor(MetadataClass javaClass) {
m_defaultAccess = null;
m_defaultSchema = null;
m_defaultCatalog = null;
m_inheritanceRootDescriptor = null;
m_inheritanceParentDescriptor = null;
m_hasCache = false;
m_hasCacheInterceptor = false;
m_hasDefaultRedirectors = false;
m_hasChangeTracking = false;
m_hasCustomizer = false;
m_hasReadOnly = false;
m_hasCopyPolicy = false;
m_hasPrimaryKey = false;
m_hasSerializedObjectPolicy = false;
m_isCascadePersist = false;
m_defaultAccessMethods = new AccessMethodsMetadata();
m_idAttributeNames = new ArrayList<String>();
m_orderByAttributeNames = new ArrayList<String>();
m_idOrderByAttributeNames = new ArrayList<String>();
m_embeddableDescriptors = new ArrayList<MetadataDescriptor>();
m_derivedIdAccessors = new ArrayList<ObjectAccessor>();
m_defaultTenantDiscriminatorColumns = new ArrayList<TenantDiscriminatorColumnMetadata>();
m_pkClassIDs = new HashMap<String, String>();
m_genericTypes = new HashMap<String, String>();
m_mappingAccessors = new HashMap<String, MappingAccessor>();
m_idAccessors = new HashMap<String, IdAccessor>();
m_fields = new HashMap<String, DatabaseField>();
m_primaryKeyAccessors = new HashMap<DatabaseField, MappingAccessor>();
m_properties = new HashMap<String, PropertyMetadata>();
m_pkJoinColumnAssociations = new HashMap<DatabaseField, DatabaseField>();
m_attributeOverrides = new HashMap<String, AttributeOverrideMetadata>();
m_associationOverrides = new HashMap<String, AssociationOverrideMetadata>();
m_biDirectionalManyToManyAccessors = new HashMap<String, Map<String, MetadataAccessor>>();
m_converts = new HashMap<String, List<ConvertMetadata>>();
m_mapKeyConverts = new HashMap<String, List<ConvertMetadata>>();
m_descriptor = new RelationalDescriptor();
m_descriptor.setAlias("");
// This is the default, set it in case no existence-checking is set.
m_descriptor.getQueryManager().checkDatabaseForDoesExist();
setJavaClass(javaClass);
}
/**
* INTERNAL:
*/
public MetadataDescriptor(MetadataClass javaClass, ClassAccessor classAccessor) {
this(javaClass);
m_classAccessor = classAccessor;
}
/**
* INTERNAL:
*/
public void addAssociationOverride(AssociationOverrideMetadata associationOverride) {
m_associationOverrides.put(associationOverride.getName(), associationOverride);
}
/**
* INTERNAL:
*/
public void addAttributeOverride(AttributeOverrideMetadata attributeOverride) {
m_attributeOverrides.put(attributeOverride.getName(), attributeOverride);
}
/**
* INTERNAL:
* Add a convert to override a superclass class mapping.
*/
public void addConvert(String attributeName, ConvertMetadata convert) {
if (convert.isForMapKey()) {
// This isForMapKey call will remove the key prefix when there is one.
addMapKeyConvert(attributeName, convert);
} else {
if (! m_converts.containsKey(attributeName)) {
m_converts.put(attributeName, new ArrayList<ConvertMetadata>());
}
m_converts.get(attributeName).add(convert);
}
}
/**
* INTERNAL:
*/
public void addDefaultEventListener(DescriptorEventListener listener) {
m_descriptor.getEventManager().addDefaultEventListener(listener);
}
/**
* INTERNAL:
*/
public void addEmbeddableDescriptor(MetadataDescriptor embeddableDescriptor) {
m_embeddableDescriptors.add(embeddableDescriptor);
}
/**
* INTERNAL:
*/
public void addEntityListenerEventListener(DescriptorEventListener listener) {
m_descriptor.getEventManager().addEntityListenerEventListener(listener);
}
/**
* INTERNAL:
* Add a field from a basic mapping from this descriptor.
*/
public void addField(DatabaseField field) {
// If it should use an upper case for comparisons upper case the name
// before putting it in the map.
m_fields.put(field.getNameForComparisons(), field);
}
/**
* INTERNAL:
*/
public void addFieldForInsert(DatabaseField field) {
getReturningPolicy().addFieldForInsert(field);
}
/**
* INTERNAL:
*/
public void addFieldForInsertReturnOnly(DatabaseField field) {
getReturningPolicy().addFieldForInsertReturnOnly(field);
}
/**
* INTERNAL:
*/
public void addFieldForUpdate(DatabaseField field) {
getReturningPolicy().addFieldForUpdate(field);
}
/**
* INTERNAL:
*/
public void addForeignKeyFieldForMultipleTable(DatabaseField fkField, DatabaseField pkField) {
m_descriptor.addForeignKeyFieldForMultipleTable(fkField, pkField);
m_pkJoinColumnAssociations.put(fkField, pkField);
}
/**
* INTERNAL:
* Add a generic type for this descriptor.
*/
public void addGenericType(String genericName, String type) {
m_genericTypes.put(genericName, type);
}
/**
* INTERNAL:
*/
public void addIdAttributeName(String idAttributeName) {
m_idAttributeNames.add(idAttributeName);
}
/**
* INTERNAL:
* Add a map key convert to override a superclass class mapping.
*/
public void addMapKeyConvert(String attributeName, ConvertMetadata convert) {
if (! m_mapKeyConverts.containsKey(attributeName)) {
m_mapKeyConverts.put(attributeName, new ArrayList<ConvertMetadata>());
}
m_mapKeyConverts.get(attributeName).add(convert);
}
/**
* INTERNAL:
* If the accessor is an IdAccessor we store it in a separate map for use
* during MappedSuperclass processing.
*/
public void addMappingAccessor(MappingAccessor accessor) {
// Don't bother adding a relationship accessor with a type of
// ValueHolderInterface. This may be very legacy and no longer needed
// but for the canonical model processing it's much cleaner if this
// accessor does not show up in the mapping accessors list.
if (accessor.isRelationship() && ((RelationshipAccessor) accessor).isValueHolderInterface()) {
return;
}
// Log a warning message if we are overriding a mapping accessor.
if (m_mappingAccessors.containsKey(accessor.getAttributeName())) {
MappingAccessor existingAccessor = m_mappingAccessors.get(accessor.getAttributeName());
String existingAccessType = existingAccessor.usesPropertyAccess() ? JPA_ACCESS_PROPERTY : JPA_ACCESS_FIELD;
String accessType = accessor.usesPropertyAccess() ? JPA_ACCESS_PROPERTY : JPA_ACCESS_FIELD;
getLogger().logWarningMessage(MetadataLogger.INVERSE_ACCESS_TYPE_MAPPING_OVERRIDE, accessor.getJavaClass().getName(), existingAccessor.getAnnotatedElementName(), existingAccessType, accessor.getAnnotatedElementName(), accessType);
}
m_mappingAccessors.put(accessor.getAttributeName(), accessor);
// Store IdAccessors in a separate map for use by hasIdAccessor()
if (accessor.isId()) {
m_idAccessors.put(accessor.getAttributeName(), (IdAccessor) accessor);
}
// Check if we already processed an EmbeddedId for this Entity or MappedSuperclass.
if (accessor.isEmbeddedId() && hasEmbeddedId()) {
throw ValidationException.multipleEmbeddedIdAnnotationsFound(getJavaClass(), accessor.getAttributeName(), this.getEmbeddedIdAttributeName());
}
// 300051: store the single EmbeddedIdAccessor for use by hasEmbeddedId in MetadataProject.addMetamodelMappedSuperclass()
if (accessor.isEmbeddedId()) {
setEmbeddedIdAccessor((EmbeddedIdAccessor)accessor);
}
}
/**
* INTERNAL:
* We store these to validate the primary class when processing the entity
* class. Note: the pk id types are always stored as their boxed type (if
* applicable). Validation should therefore always be done against boxed
* types.
*
* @see validateDerivedPKClassId
* @see validatePKClassId
*/
public void addPKClassId(String attributeName, String type) {
m_pkClassIDs.put(attributeName, type);
}
/**
* INTERNAL:
* Add a property to the descriptor. Will check for an override/ignore case.
*/
public void addProperty(PropertyMetadata property) {
if (property.shouldOverride(m_properties.get(property.getName()))) {
m_properties.put(property.getName(), property);
m_descriptor.addUnconvertedProperty(property.getName(), property.getValue(), property.getJavaClassName(property.getValueType()));
}
}
/**
* INTERNAL:
* Add a field representing the primary key or part of a composite primary
* key to the List of primary key fields on the relational descriptor
* associated with this metadata descriptor. Call this method if there
* is no associated mapping accessor, e.g. a PrimaryKey annotation
* specification or a derived id mapping. Otherwise, regular JPA id mappings
* should call addPrimaryKeyField(DatabaseField, MappingAccessor)
*/
public void addPrimaryKeyField(DatabaseField field) {
// Make sure the field has a table set.
if (! field.hasTableName()) {
field.setTable(getPrimaryTable());
}
// Add the field to the class descriptor.
m_descriptor.addPrimaryKeyField(field);
// Add the field to our internal field map.
addField(field);
}
/**
* INTERNAL:
* Add a field representing the primary key or part of a composite primary
* key to the List of primary key fields on the relational descriptor
* associated with this metadata descriptor.
*/
public void addPrimaryKeyField(DatabaseField field, MappingAccessor accessor) {
addPrimaryKeyField(field);
// Store the primary key field mappings keyed on their field name.
m_primaryKeyAccessors.put(field, accessor);
}
/**
* INTERNAL:
* Store relationship accessors for later processing and quick look up.
*/
public void addRelationshipAccessor(RelationshipAccessor accessor) {
getProject().addRelationshipAccessor(accessor);
// Store bidirectional ManyToMany relationships so that we may look at
// attribute names when defaulting join columns.
if (accessor.isManyToMany()) {
if (accessor.hasMappedBy()) {
String referenceClassName = accessor.getReferenceClassName();
// Initialize the map of bi-directional mappings for this class.
if (! m_biDirectionalManyToManyAccessors.containsKey(referenceClassName)) {
m_biDirectionalManyToManyAccessors.put(referenceClassName, new HashMap<String, MetadataAccessor>());
}
m_biDirectionalManyToManyAccessors.get(referenceClassName).put(accessor.getMappedBy(), accessor);
}
}
}
/**
* INTERNAL:
*/
public void addTable(DatabaseTable table) {
m_descriptor.addTable(table);
}
/**
* INTERNAL:
* This method is called only for canonical model generation during the
* pre-processing stage. Canonical model generation needs to rebuild its
* accessor list from one compile round to another within Eclipse. This
* should not be called otherwise.
*
* Anything that is set in the addAccessor(MappingAccessor) method should
* be cleared here.
*/
public void clearMappingAccessors() {
m_mappingAccessors.clear();
m_embeddedIdAccessor = null;
}
/**
* INTERNAL:
*/
public boolean excludeSuperclassListeners() {
return m_descriptor.getEventManager().excludeSuperclassListeners();
}
/**
* INTERNAL:
*/
public String getAlias() {
return m_descriptor.getAlias();
}
/**
* INTERNAL:
*/
public AssociationOverrideMetadata getAssociationOverrideFor(String attributeName) {
return m_associationOverrides.get(attributeName);
}
/**
* INTERNAL:
*/
public Collection<AssociationOverrideMetadata> getAssociationOverrides() {
return m_associationOverrides.values();
}
/**
* INTERNAL:
*/
public AttributeOverrideMetadata getAttributeOverrideFor(String attributeName) {
return m_attributeOverrides.get(attributeName);
}
/**
* INTERNAL:
*/
public Collection<AttributeOverrideMetadata> getAttributeOverrides() {
return m_attributeOverrides.values();
}
/**
* INTERNAL:
*/
public ClassAccessor getClassAccessor() {
return m_classAccessor;
}
/**
* INTERNAL:
* Return the RelationalDescriptor instance associated with this MetadataDescriptor
*/
public ClassDescriptor getClassDescriptor() {
return m_descriptor;
}
/**
* INTERNAL:
*/
public CMPPolicy getCMPPolicy() {
return m_descriptor.getCMPPolicy();
}
/**
* INTERNAL:
*/
public List<ConvertMetadata> getConverts(String attributeName) {
return m_converts.get(attributeName);
}
/**
* INTERNAL:
*/
public String getDefaultAccess() {
return m_defaultAccess;
}
/**
* INTERNAL:
*/
public AccessMethodsMetadata getDefaultAccessMethods() {
return m_defaultAccessMethods;
}
/**
* INTERNAL:
*/
public String getDefaultCatalog() {
return m_defaultCatalog;
}
/**
* INTERNAL:
*/
public String getDefaultSchema() {
return m_defaultSchema;
}
/**
* INTERNAL:
*/
public List<TenantDiscriminatorColumnMetadata> getDefaultTenantDiscriminatorColumns() {
return m_defaultTenantDiscriminatorColumns;
}
/**
* INTERNAL:
* The default table name is the descriptor alias, unless this descriptor
* metadata is an inheritance subclass with a SINGLE_TABLE strategy. Then
* it is the table name of the root descriptor metadata.
*/
public String getDefaultTableName() {
String defaultTableName =(getProject().useDelimitedIdentifier()) ? getAlias() : getAlias().toUpperCase(Locale.ROOT);
if (isInheritanceSubclass()) {
if (getInheritanceRootDescriptor().usesSingleTableInheritanceStrategy()) {
defaultTableName = getInheritanceRootDescriptor().getPrimaryTableName();
}
}
return defaultTableName;
}
/**
* INTERNAL:
*/
public List<ObjectAccessor> getDerivedIdAccessors(){
return m_derivedIdAccessors;
}
/**
* INTERNAL:
* Return the embedded id accessor for this descriptor if one exists.
*/
public EmbeddedIdAccessor getEmbeddedIdAccessor() {
return m_embeddedIdAccessor;
}
/**
* INTERNAL:
*/
public String getEmbeddedIdAttributeName() {
return m_embeddedIdAccessor.getAttributeName();
}
/**
* INTERNAL:
* This method assumes that by calling this method you are certain that
* the related class accessor to this descriptor is an EntityAccessor.
* You should not call this method otherwise, @see getClassAccessor()
*/
public EntityAccessor getEntityAccessor() {
return (EntityAccessor) m_classAccessor;
}
/**
* INTERNAL:
* Return the DatabaseField from the given field name from this descriptor.
* It also checks primary key fields and parent descriptors.
*/
public DatabaseField getField(String fieldName) {
if (! m_fields.containsKey(fieldName) && isInheritanceSubclass()) {
return getInheritanceRootDescriptor().getField(fieldName);
} else {
return m_fields.get(fieldName);
}
}
/**
* INTERNAL:
* Return the type from the generic name.
*/
public String getGenericType(String genericName) {
return m_genericTypes.get(genericName);
}
/**
* INTERNAL:
*/
public Map getGenericTypes() {
return m_genericTypes;
}
/**
* INTERNAL:
*/
public Map<String, IdAccessor> getIdAccessors() {
return m_idAccessors;
}
/**
* INTERNAL:
* Return the primary key attribute name for this entity.
*/
public String getIdAttributeName() {
if (getIdAttributeNames().isEmpty()) {
if (isInheritanceSubclass()) {
return getInheritanceRootDescriptor().getIdAttributeName();
} else {
return "";
}
} else {
return getIdAttributeNames().get(0);
}
}
/**
* INTERNAL:
* Return the id attribute names declared on this descriptor metadata.
*/
public List<String> getIdAttributeNames() {
return m_idAttributeNames;
}
/**
* INTERNAL:
* Return the primary key attribute names for this entity. If there are no
* id attribute names set then we are either:
* 1) an inheritance subclass, get the id attribute names from the root
* of the inheritance structure.
* 2) we have an embedded id. Get the id attribute names from the embedded
* descriptor metadata, which is equal the attribute names of all the
* direct to field mappings on that descriptor metadata. Currently does
* not traverse nested embeddables.
*/
public List<String> getIdOrderByAttributeNames() {
if (m_idOrderByAttributeNames.isEmpty()) {
if (m_idAttributeNames.isEmpty()) {
if (isInheritanceSubclass()) {
// Get the id attribute names from our root parent.
m_idOrderByAttributeNames = getInheritanceRootDescriptor().getIdAttributeNames();
} else {
// We must have a composite primary key as a result of an embedded id.
m_idOrderByAttributeNames = getMappingAccessor(getEmbeddedIdAttributeName()).getReferenceDescriptor().getOrderByAttributeNames();
}
} else {
m_idOrderByAttributeNames = m_idAttributeNames;
}
}
return m_idOrderByAttributeNames;
}
/**
* INTERNAL:
* Assumes hasBidirectionalManyToManyAccessorFor has been called before
* hand.
*/
public MetadataAccessor getBiDirectionalManyToManyAccessor(String className, String attributeName) {
return m_biDirectionalManyToManyAccessors.get(className).get(attributeName);
}
/**
* INTERNAL:
* Returns the immediate parent's descriptor in the inheritance hierarchy.
*/
public MetadataDescriptor getInheritanceParentDescriptor() {
return m_inheritanceParentDescriptor;
}
/**
* INTERNAL:
* Returns the root descriptor of the inheritance hierarchy, that is, the
* one that defines the inheritance strategy.
*/
public MetadataDescriptor getInheritanceRootDescriptor() {
return m_inheritanceRootDescriptor;
}
/**
* INTERNAL:
*/
public MetadataClass getJavaClass() {
return m_javaClass;
}
/**
* INTERNAL:
*/
public String getJavaClassName() {
return m_descriptor.getJavaClassName();
}
/**
* INTERNAL:
*/
public MetadataLogger getLogger() {
return getProject().getLogger();
}
/**
* INTERNAL:
*/
public List<ConvertMetadata> getMapKeyConverts(String attributeName) {
return m_mapKeyConverts.get(attributeName);
}
/**
* INTERNAL:
* This method will first check for an accessor with name equal to field or
* property name. If no accessor is found than it assumes the field or
* property name passed in may be a method name and converts it to its
* corresponding property name and looks for the accessor again. If still no
* accessor is found and this descriptor represents an inheritance subclass,
* then traverse up the chain to look for that accessor. Null is returned
* otherwise.
*/
public MappingAccessor getMappingAccessor(String fieldOrPropertyName) {
return getMappingAccessor(fieldOrPropertyName, true);
}
/**
* INTERNAL:
* This method will first check for an accessor with name equal to field or
* property name. If no accessor is found and the checkForMethodName flag is
* set to true then we'll attempt to convert a potential method name to its
* corresponding property name and looks for the accessor again. If still no
* accessor is found and this descriptor represents an inheritance subclass,
* then traverse up the chain to look for that accessor. Null is returned
* otherwise.
*/
protected MappingAccessor getMappingAccessor(String fieldOrPropertyName, boolean checkForMethodName) {
MappingAccessor accessor = m_mappingAccessors.get(fieldOrPropertyName);
if (accessor == null) {
// Perhaps we have a method name. This is value add, and maybe we
// really shouldn't do this but it covers the following case:
// <order-by>age, getGender DESC</order-by>, where the user
// specifies a method name.
if (checkForMethodName) {
accessor = m_mappingAccessors.get(Helper.getAttributeNameFromMethodName(fieldOrPropertyName));
}
// If still no accessor and we are an inheritance subclass, check
// our parent descriptor. Unless we are within a table per class
// strategy in which case, if the mapping doesn't exist within our
// accessor list, we don't want to deal with it.
if (accessor == null && isInheritanceSubclass() && ! usesTablePerClassInheritanceStrategy()) {
accessor = getInheritanceParentDescriptor().getMappingAccessor(fieldOrPropertyName, checkForMethodName);
}
}
if (accessor == null) {
// Traverse any dot notation (nested embeddables) if specified.
int idx = fieldOrPropertyName.indexOf('.');
if (idx > -1) {
String attributeName = fieldOrPropertyName.substring(0, idx);
String subAttributeName = fieldOrPropertyName.substring(idx + 1);
MappingAccessor embeddedAccessor = m_mappingAccessors.get(attributeName);
if (embeddedAccessor != null) {
accessor = embeddedAccessor.getReferenceDescriptor().getMappingAccessor(subAttributeName, checkForMethodName);
}
}
// If we are still null, maybe the user has not used a dot notation
// that is, has not been fully specific. At this point this is value
// add in that we will dig through the embeddable descriptors and
// look for and return the first mapping for the given attribute
// name. This could be error prone, but looks like we have a number
// of tests that don't use the dot notation.
if (accessor == null) {
// We didn't find an accessor on our descriptor (or a parent
// descriptor), check our aggregate descriptors now.
for (MetadataDescriptor embeddableDescriptor : m_embeddableDescriptors) {
// If the attribute name employs the dot notation, rip off
// the first bit (up to the first dot and keep burying down
// the embeddables)
String subAttributeName = fieldOrPropertyName;
if (subAttributeName.contains(".")) {
subAttributeName = subAttributeName.substring(fieldOrPropertyName.indexOf('.') + 1);
}
accessor = embeddableDescriptor.getMappingAccessor(fieldOrPropertyName, checkForMethodName);
if (accessor != null) {
// Found one, stop looking ...
break;
}
}
}
}
return accessor;
}
/**
* INTERNAL:
* Return the collection of mapping accessors for this descriptor.
*/
public Collection<MappingAccessor> getMappingAccessors() {
return m_mappingAccessors.values();
}
/**
* INTERNAL:
*/
public DatabaseMapping getMappingForAttributeName(String attributeName) {
return getMappingAccessor(attributeName).getMapping();
}
/**
* INTERNAL:
*/
public List<DatabaseMapping> getMappings() {
return m_descriptor.getMappings();
}
/**
* INTERNAL:
*/
public MetadataDescriptor getMetamodelMappedSuperclassChildDescriptor() {
return m_metamodelMappedSuperclassChildDescriptor;
}
/**
* INTERNAL:
* This will return the attribute names for all the direct to field mappings
* on this descriptor metadata. This method will typically be called when an
* embedded or embedded id attribute has been specified as an order by
* field
*/
public List<String> getOrderByAttributeNames() {
if (m_orderByAttributeNames.isEmpty()) {
for (DatabaseMapping mapping : getMappings()) {
if (mapping.isDirectToFieldMapping()) {
m_orderByAttributeNames.add(mapping.getAttributeName());
}
}
}
return m_orderByAttributeNames;
}
/**
* INTERNAL:
*/
public MetadataClass getPKClass(){
return m_pkClass;
}
/**
* INTERNAL:
*/
public Map<String, String> getPKClassIDs() {
return m_pkClassIDs;
}
/**
* INTERNAL:
*/
public String getPKClassName() {
String pkClassName = null;
if (m_descriptor.hasCMPPolicy()) {
pkClassName = ((CMP3Policy) m_descriptor.getCMPPolicy()).getPKClassName();
}
return pkClassName;
}
/**
* INTERNAL:
* Return the primary key mapping for the given field.
*/
public MappingAccessor getPrimaryKeyAccessorForField(DatabaseField field) {
return m_primaryKeyAccessors.get(field);
}
/**
* INTERNAL:
* Method to return the primary key field name this descriptor metadata.
* It assumes there is one.
*/
public DatabaseField getPrimaryKeyField() {
return getPrimaryKeyFields().iterator().next();
}
/**
* INTERNAL:
* Method to return the primary key field name for this descriptor metadata.
* It assumes there is one.
*/
public String getPrimaryKeyFieldName() {
return getPrimaryKeyField().getName();
}
/**
* INTERNAL
* Return the primary key fields for this descriptor metadata. If this is
* an inheritance subclass and it has no primary key fields, then grab the
* primary key fields from the root. In a table per class inheritance
* strategy, the primary key fields (and all mappings for that matter) are
* inherited from the parent meaning there is no need to check the parent
* in this case, it should have primary key fields and checking the parent
* could lead to processing errors.
*/
public List<DatabaseField> getPrimaryKeyFields() {
List<DatabaseField> primaryKeyFields = m_descriptor.getPrimaryKeyFields();
if (primaryKeyFields.isEmpty() && isInheritanceSubclass() && ! usesTablePerClassInheritanceStrategy()) {
primaryKeyFields = getInheritanceRootDescriptor().getPrimaryKeyFields();
}
return primaryKeyFields;
}
/**
* INTERNAL:
* Recursively check the potential chaining of the primary key fields from
* a inheritance subclass, all the way to the root of the inheritance
* hierarchy.
*/
public DatabaseField getPrimaryKeyJoinColumnAssociation(DatabaseField foreignKey) {
DatabaseField primaryKey = m_pkJoinColumnAssociations.get(foreignKey);
if ( primaryKey == null || primaryKey.getName() == null || ! isInheritanceSubclass()) {
return foreignKey;
} else {
return getInheritanceParentDescriptor().getPrimaryKeyJoinColumnAssociation(primaryKey);
}
}
/**
* INTERNAL:
* Returns the first primary key join column association if there is one.
* Otherwise, the primary key field given is returned.
*/
public DatabaseField getPrimaryKeyJoinColumnAssociationField(DatabaseField primaryKeyField) {
if (! m_pkJoinColumnAssociations.isEmpty()) {
return m_pkJoinColumnAssociations.keySet().iterator().next();
}
return primaryKeyField;
}
/**
* INTERNAL:
* Assumes there is one primary key field set. This method should be called
* when qualifying any primary key field (from a join column) for this
* descriptor. This method was created because in an inheritance hierarchy
* with a joined strategy we can't use getPrimaryTableName() since it would
* return the wrong table name. From the spec, the primary key must be
* defined on the entity that is the root of the entity hierarchy or on a
* mapped superclass of the entity hierarchy. The primary key must be
* defined exactly once in an entity hierarchy.
*/
public DatabaseTable getPrimaryKeyTable() {
return getPrimaryKeyField().getTable();
}
/**
* INTERNAL:
*/
public DatabaseTable getPrimaryTable() {
if (m_primaryTable == null && isInheritanceSubclass()) {
return getInheritanceRootDescriptor().getPrimaryTable();
} else {
if (m_descriptor.isAggregateDescriptor()) {
// Aggregate descriptors don't have tables, just return a
// a default empty table.
return new DatabaseTable();
}
return m_primaryTable;
}
}
/**
* INTERNAL:
*/
public String getPrimaryTableName() {
return getPrimaryTable().getName();
}
/**
* INTERNAL:
*/
public MetadataProject getProject() {
return getClassAccessor().getProject();
}
/**
* INTERNAL:
*/
protected ReturningPolicy getReturningPolicy() {
if (! m_descriptor.hasReturningPolicy()) {
m_descriptor.setReturningPolicy(new ReturningPolicy());
}
return m_descriptor.getReturningPolicy();
}
/**
* INTERNAL:
*/
public DatabaseField getSequenceNumberField() {
return m_descriptor.getSequenceNumberField();
}
/**
* INTERNAL:
* Assumes a call to hasSingleTableMultitenant has been made before hand.
*/
public Map<String, List<DatabaseField>> getSingleTableMultitenantFields() {
return ((SingleTableMultitenantPolicy) m_descriptor.getMultitenantPolicy()).getTenantDiscriminatorFieldsKeyedOnContext();
}
/**
* INTERNAL:
* Returns true is an additional criteria has been set on this descriptor's
* query manager.
*/
public boolean hasAdditionalCriteria() {
return m_descriptor.getQueryManager().hasAdditionalCriteria();
}
/**
* INTERNAL:
*/
public boolean hasAssociationOverrideFor(String attributeName) {
return m_associationOverrides.containsKey(attributeName);
}
/**
* INTERNAL:
*/
public boolean hasAttributeOverrideFor(String attributeName) {
return m_attributeOverrides.containsKey(attributeName);
}
/**
* INTERNAL:
*/
public boolean hasCompositePrimaryKey() {
return getPrimaryKeyFields().size() > 1 || getPKClass() != null;
}
/**
* INTERNAL:
*/
public boolean hasEmbeddedId() {
return m_embeddedIdAccessor != null;
}
/**
* INTERNAL:
*/
public boolean hasExistenceChecking() {
return m_existenceChecking != null;
}
/**
* INTERNAL:
*/
public boolean hasBiDirectionalManyToManyAccessorFor(String className, String attributeName) {
if (m_biDirectionalManyToManyAccessors.containsKey(className)) {
return m_biDirectionalManyToManyAccessors.get(className).containsKey(attributeName);
}
return false;
}
/**
* INTERNAL:
* Indicates that a Cache annotation or cache element has already been
* processed for this descriptor.
*/
public boolean hasCache() {
return m_hasCache;
}
/**
* INTERNAL:
* Indicates that a Cacheable annotation or cache element has already been
* processed for this descriptor.
*/
public boolean hasCacheable() {
return m_cacheable != null;
}
/**
* INTERNAL:
* Indicates that a CacheInterceptor annotation or cacheInterceptor element has already been
* processed for this descriptor.
*/
public boolean hasCacheInterceptor() {
return m_hasCacheInterceptor;
}
/**
* INTERNAL:
* Indicates that a DefaultRedirectors annotation or default-redirectors element has already been
* processed for this descriptor.
*/
public boolean hasDefaultRedirectors() {
return m_hasDefaultRedirectors;
}
/**
* INTERNAL:
* Indicates that a Change tracking annotation or change tracking element
* has already been processed for this descriptor.
*/
public boolean hasChangeTracking() {
return m_hasChangeTracking;
}
/**
* INTERNAL:
* Indicates that a copy Policy annotation or copy policy element
* has already been processed for this descriptor.
*/
public boolean hasCopyPolicy() {
return m_hasCopyPolicy;
}
/**
* INTERNAL:
* Return true if there is convert metadata for the given attribute name.
*/
public boolean hasConverts(String attributeName) {
return m_converts.containsKey(attributeName);
}
/**
* INTERNAL:
* Indicates that a customizer annotation or customizer element has already
* been processed for this descriptor.
*/
public boolean hasCustomizer() {
return m_hasCustomizer;
}
/**
* INTERNAL:
* Return whether there is an IdAccessor on this descriptor.
*/
public boolean hasIdAccessor() {
return ! m_idAccessors.isEmpty();
}
/**
* INTERNAL:
* Return true if there is map key convert metadata for the given attribute
* name.
*/
public boolean hasMapKeyConverts(String attributeName) {
return m_mapKeyConverts.containsKey(attributeName);
}
/**
* INTERNAL:
* Returns true if we already have (processed) an accessor for the given
* attribute name.
*/
public boolean hasMappingAccessor(String attributeName) {
return getMappingAccessor(attributeName, false) != null;
}
/**
* INTERNAL:
*/
public boolean hasMappingForAttributeName(String attributeName) {
return m_descriptor.getMappingForAttributeName(attributeName) != null;
}
/**
* INTERNAL:
* Indicates if multitenant metadata has been processed for this descriptor.
*/
public boolean hasMultitenant() {
return m_descriptor.hasMultitenantPolicy();
}
/**
* INTERNAL:
*/
public boolean hasPKClass() {
return m_pkClass != null;
}
/**
* INTERNAL:
* Indicates that a PrimaryKey annotation or primary-key element has been
* processed for this descriptor.
*/
public boolean hasPrimaryKey() {
return m_hasPrimaryKey;
}
/**
* INTERNAL:
* Return true is the descriptor has primary key fields set.
*/
public boolean hasPrimaryKeyFields() {
return m_descriptor.getPrimaryKeyFields().size() > 0;
}
/**
* INTERNAL:
* Indicates that a read only annotation or read only element has already
* been processed for this descriptor.
*/
public boolean hasReadOnly() {
return m_hasReadOnly;
}
/**
* INTERNAL:
* Indicates if single table multitenant metadata has been processed for
* this descriptor.
*/
public boolean hasSingleTableMultitenant() {
return hasMultitenant() && m_descriptor.getMultitenantPolicy().isSingleTableMultitenantPolicy();
}
/**
* INTERNAL:
* Indicates that a SerializedObject annotation or serialized-object element has been
* processed for this descriptor.
*/
public boolean m_hasSerializedObjectPolicy() {
return m_hasSerializedObjectPolicy;
}
/**
* INTERNAL:
* Indicates that an explicit cacheable value of true has been set for
* this descriptor.
*/
public boolean isCacheableTrue() {
if (m_cacheable != null) {
return m_cacheable;
} else if (isInheritanceSubclass()) {
return getInheritanceParentDescriptor().isCacheableTrue();
}
return false;
}
/**
* INTERNAL:
* Indicates that an explicit cacheable value of false has been set for
* this descriptor.
*/
public boolean isCacheableFalse() {
if (m_cacheable != null) {
return !m_cacheable;
} else if (isInheritanceSubclass()) {
return getInheritanceParentDescriptor().isCacheableFalse();
}
return false;
}
/**
* INTERNAL:
* Indicates that cascade-persist should be applied to all relationship
* mappings for this entity.
*/
public boolean isCascadePersist() {
return m_isCascadePersist;
}
/**
* INTERNAL:
*/
public boolean isEmbeddable() {
return m_descriptor.isAggregateDescriptor();
}
/**
* INTERNAL:
*/
public boolean isEmbeddableCollection() {
return m_descriptor.isAggregateCollectionDescriptor();
}
/**
* INTERNAL:
*/
public boolean isInheritanceSubclass() {
return m_inheritanceParentDescriptor != null;
}
/**
* INTERNAL:
* Return whether the ClassAccessor on this MetadataDescriptor is a MappedSuperclassAccessor.
* @since EclipseLink 1.2 for the JPA 2.0 Reference Implementation
*/
public boolean isMappedSuperclass() {
return getClassAccessor().isMappedSuperclass();
}
/**
* INTERNAL:
*/
public boolean pkClassWasNotValidated() {
return ! m_pkClassIDs.isEmpty();
}
/**
* INTERNAL:
* Process this descriptors mapping accessors. Some accessors will not be
* processed right away, instead stored on the project for processing in a
* later stage. This method can not and must not be called beyond
* MetadataProject stage 2 processing.
*/
public void processMappingAccessors() {
for (MappingAccessor accessor : m_mappingAccessors.values()) {
if (! accessor.isProcessed()) {
// If we a mapped key map accessor with an embeddable as the
// key, process that embeddable accessor now.
if (accessor.isMappedKeyMapAccessor()) {
MappedKeyMapAccessor mapAccessor = (MappedKeyMapAccessor) accessor;
EmbeddableAccessor mapKeyEmbeddableAccessor = getProject().getEmbeddableAccessor(mapAccessor.getMapKeyClass());
if (mapKeyEmbeddableAccessor != null && ! mapKeyEmbeddableAccessor.isProcessed()) {
mapKeyEmbeddableAccessor.process();
}
}
// We need to defer the processing of some mappings to stage
// 3 processing. Accessors are added to different lists since
// the order or processing of those accessors is important.
// See MetadataProject.processStage2() for more details.
// Care must be taken in the order of checking here.
if (accessor.isDirectEmbeddableCollection() || accessor.isEmbedded()) {
EmbeddableAccessor embeddableAccessor = getProject().getEmbeddableAccessor(accessor.getReferenceClass());
// If there is no embeddable accessor at this point,
// something is wrong, throw an exception. Note a direct
// embeddable collection can't hit here since we don't build
// a direct embeddable collection if the reference class is
// not an Embeddable.
if (embeddableAccessor == null) {
throw ValidationException.invalidEmbeddedAttribute(getJavaClass(), accessor.getAttributeName(), accessor.getReferenceClass());
} else {
// Process the embeddable class now (if it's not already processed)
if (! embeddableAccessor.isProcessed()) {
embeddableAccessor.process();
}
// Store this descriptor metadata. It may be needed again
// later on to look up a mappedBy attribute etc.
addEmbeddableDescriptor(embeddableAccessor.getDescriptor());
// Since association overrides are not allowed on
// embeddedid's we can and must process it right now,
// instead of deferring it till after the relationship
// accessors have processed.
if (accessor.isEmbeddedId() || accessor.isDerivedIdClass()) {
accessor.process();
} else {
// Otherwise defer it because of association overrides.
// We can't process this mapping till all the
// relationship mappings have been processed.
getProject().addEmbeddableMappingAccessor(accessor);
}
}
} else if (accessor.isDirectCollection()) {
getProject().addDirectCollectionAccessor(accessor);
} else if (accessor.isRelationship()) {
if (accessor.derivesId()) {
m_derivedIdAccessors.add((ObjectAccessor) accessor);
getProject().addAccessorWithDerivedId(m_classAccessor);
} else {
addRelationshipAccessor((RelationshipAccessor) accessor);
}
} else {
accessor.process();
}
}
}
}
/**
* INTERNAL:
* Remove the following field from the primary key field lists. Presumably,
* it is not a primary key field or is being replaced with another. See
* EmbeddedAccessor processAttributeOverride method.
*/
public void removePrimaryKeyField(DatabaseField field) {
// Remove the field from the class descriptor list.
m_descriptor.getPrimaryKeyFields().remove(field);
// Remove the primary key field and accessor.
m_primaryKeyAccessors.remove(field);
}
/**
* INTERNAL:
* Record whether this descriptor uses property access. This information is used to
* modify the behavior of some of our weaving features
*/
public void setAccessTypeOnClassDescriptor(String accessType){
if (accessType.equals(JPA_ACCESS_PROPERTY)) {
m_descriptor.usePropertyAccessForWeaving();
}
}
/**
* INTERNAL:
*/
public void setAlias(String alias) {
m_descriptor.setAlias(alias);
}
/**
* INTERNAL:
* Get entity @Cacheable annotation value.
* @return Entity @Cacheable annotation value. This value refers to current
* class only and does not contain inherited value from parent
* classes.
*/
public Boolean getCacheable() {
return m_cacheable;
}
/**
* INTERNAL:
* Set entity @Cacheable annotation value.
* @param cacheable Entity @Cacheable annotation value. This value refers
* to current class only and does not contain inherited value from
* parent classes.
*/
public void setCacheable(Boolean cacheable) {
m_cacheable = cacheable;
}
/**
* INTERNAL:
* Pass entity @Cacheable annotation value to cache configuration object
* in class descriptor.
*/
public void setCacheableInDescriptor() {
m_descriptor.setCacheable(m_cacheable);
}
/**
* INTERNAL:
*/
public void setClassAccessor(ClassAccessor accessor) {
m_classAccessor = accessor;
}
/**
* INTERNAL:
*/
public void setDefaultAccess(String defaultAccess) {
m_defaultAccess = defaultAccess;
}
/**
* INTERNAL:
* Default access methods can come from the following locations
* (in XML only) :
* - persistence-unit-defaults
* - entity-mappings
* - entity
* - embeddable
*
* Be default, the default access methods are set to use "get" and "set"
* unless they are overridden by discovering access methods specified at
* one of the locations above.
*/
public void setDefaultAccessMethods(AccessMethodsMetadata accessMethods) {
m_defaultAccessMethods = accessMethods;
getClassDescriptor().getVirtualAttributeMethods().add(new VirtualAttributeMethodInfo(accessMethods.getGetMethodName(),accessMethods.getSetMethodName()));
}
/**
* INTERNAL:
*/
public void setDefaultCatalog(String defaultCatalog) {
m_defaultCatalog = defaultCatalog;
}
/**
* INTERNAL:
*/
public void setDefaultSchema(String defaultSchema) {
m_defaultSchema = defaultSchema;
}
/**
* INTERNAL:
*/
public void setDefaultTenantDiscriminatorColumns(List<TenantDiscriminatorColumnMetadata> defaultTenantDiscriminatorColumns) {
m_defaultTenantDiscriminatorColumns = defaultTenantDiscriminatorColumns;
}
/**
* INTERNAL:
* Set the RelationalDescriptor instance associated with this MetadataDescriptor
*/
public void setDescriptor(ClassDescriptor descriptor) {
m_descriptor = descriptor;
}
/**
* INTERNAL:
*/
public void setEmbeddedIdAccessor(EmbeddedIdAccessor embeddedIdAccessor) {
m_embeddedIdAccessor = embeddedIdAccessor;
}
/**
* INTERNAL:
*/
public void setEntityEventListener(EntityListener listener) {
m_descriptor.getEventManager().setEntityEventListener(listener);
}
/**
* INTERNAL:
*/
public void setExcludeDefaultListeners(boolean excludeDefaultListeners) {
m_descriptor.getEventManager().setExcludeDefaultListeners(excludeDefaultListeners);
}
/**
* INTERNAL:
*/
public void setExcludeSuperclassListeners(boolean excludeSuperclassListeners) {
m_descriptor.getEventManager().setExcludeSuperclassListeners(excludeSuperclassListeners);
}
/**
* INTERNAL:
*/
public void setExistenceChecking(String existenceChecking) {
m_existenceChecking = existenceChecking;
if (existenceChecking.equals(ExistenceType.CHECK_CACHE.name())) {
m_descriptor.getQueryManager().checkCacheForDoesExist();
} else if (existenceChecking.equals(ExistenceType.CHECK_DATABASE.name())) {
m_descriptor.getQueryManager().checkDatabaseForDoesExist();
} else if (existenceChecking.equals(ExistenceType.ASSUME_EXISTENCE.name())) {
m_descriptor.getQueryManager().assumeExistenceForDoesExist();
} else if (existenceChecking.equals(ExistenceType.ASSUME_NON_EXISTENCE.name())) {
m_descriptor.getQueryManager().assumeNonExistenceForDoesExist();
}
}
/**
* INTERNAL:
* Indicates that we have processed a cache annotation or cache xml element.
*/
public void setHasCache() {
m_hasCache = true;
}
/**
* INTERNAL:
* Indicates that we have processed a cache annotation or cache xml element.
*/
public void setHasCacheInterceptor() {
m_hasCacheInterceptor = true;
}
/**
* INTERNAL:
* Indicates that we have processed a customizer annotation or customizer
* xml element.
*/
public void setHasCustomizer() {
m_hasCustomizer = true;
}
/**
* INTERNAL:
* Indicates that we have processed a cache annotation or cache xml element.
*/
public void setHasDefaultRedirectors() {
m_hasDefaultRedirectors = true;
}
/**
* INTERNAL:
* Indicates that we have processed a PrimaryKey annotation or primary-key
* xml element.
*/
public void setHasPrimaryKey() {
m_hasPrimaryKey = true;
}
/**
* INTERNAL:
* Indicates that we have processed a change tracking annotation or change
* tracking xml element.
*/
public void setHasChangeTracking() {
m_hasChangeTracking = true;
}
/**
* INTERNAL:
* Indicates that we have processed a copy policy annotation or copy policy xml element.
*/
public void setHasCopyPolicy() {
m_hasCopyPolicy = true;
}
/**
* INTERNAL:
* Indicates that we have processed a serialized object annotation or serialized object xml element.
*/
public void setHasSerializedObjectPolicy() {
m_hasSerializedObjectPolicy = true;
}
/**
* INTERNAL:
* Set the immediate parent's descriptor of the inheritance hierarchy.
*/
public void setInheritanceParentDescriptor(MetadataDescriptor inheritanceParentDescriptor) {
m_inheritanceParentDescriptor = inheritanceParentDescriptor;
}
/**
* INTERNAL:
* Set the root descriptor of the inheritance hierarchy, that is, the one
* that defines the inheritance strategy.
*/
public void setInheritanceRootDescriptor(MetadataDescriptor inheritanceRootDescriptor) {
m_inheritanceRootDescriptor = inheritanceRootDescriptor;
}
/**
* INTERNAL:
* Indicates that cascade-persist should be added to the set of cascade
* values for all relationship mappings.
*/
public void setIsCascadePersist(boolean isCascadePersist) {
m_isCascadePersist = isCascadePersist;
}
/**
* INTERNAL:
*/
public void setIsEmbeddable() {
m_descriptor.descriptorIsAggregate();
}
/**
* INTERNAL:
* Used to set this descriptors java class.
*/
public void setJavaClass(MetadataClass javaClass) {
m_javaClass = javaClass;
m_descriptor.setJavaClassName(javaClass.getName());
// If the javaClass is an interface, add it to the java interface name
// on the relational descriptor.
if (javaClass.isInterface()) {
m_descriptor.setJavaInterfaceName(javaClass.getName());
}
}
/**
* INTERNAL:
*/
public void setMetamodelMappedSuperclassChildDescriptor(MetadataDescriptor childDescriptor) {
m_metamodelMappedSuperclassChildDescriptor = childDescriptor;
}
/**
* INTERNAL:
*/
public void setOptimisticLockingPolicy(OptimisticLockingPolicy policy) {
m_descriptor.setOptimisticLockingPolicy(policy);
}
/**
* INTERNAL:
*/
public void setPKClass(MetadataClass pkClass) {
m_pkClass = pkClass;
CMP3Policy policy = new CMP3Policy();
policy.setPrimaryKeyClassName(pkClass.getName());
m_descriptor.setCMPPolicy(policy);
}
/**
* INTERNAL:
*/
public void setPrimaryTable(DatabaseTable primaryTable) {
addTable(primaryTable);
m_primaryTable = primaryTable;
}
/**
* INTERNAL:
*/
public void setReadOnly(boolean readOnly) {
if (readOnly) {
m_descriptor.setReadOnly();
}
m_hasReadOnly = true;
}
/**
* INTERNAL:
*/
public void setSequenceNumberField(DatabaseField field) {
m_descriptor.setSequenceNumberField(field);
}
/**
* INTERNAL:
*/
public void setSequenceNumberName(String name) {
m_descriptor.setSequenceNumberName(name);
}
/**
* INTERNAL:
*/
public void setUsesCascadedOptimisticLocking(Boolean usesCascadedOptimisticLocking) {
m_usesCascadedOptimisticLocking = usesCascadedOptimisticLocking;
}
/**
* INTERNAL:
*/
@Override
public String toString() {
return getJavaClassName();
}
/**
* INTERNAL:
*/
public void useNoCache() {
m_descriptor.setCacheIsolation(CacheIsolationType.ISOLATED);
}
/**
* INTERNAL:
*/
public boolean usesCascadedOptimisticLocking() {
return m_usesCascadedOptimisticLocking != null && m_usesCascadedOptimisticLocking;
}
/**
* INTERNAL:
* Returns true if this class uses default property access. All access
* discovery and processing should have been performed before calling
* this method and a default access type should have been set.
*/
public boolean usesDefaultPropertyAccess() {
return m_defaultAccess.equals(JPA_ACCESS_PROPERTY);
}
/**
* INTERNAL:
*/
public boolean usesOptimisticLocking() {
return m_descriptor.usesOptimisticLocking();
}
/**
* INTERNAL:
* Indicates if the strategy on the descriptor's inheritance policy is
* SINGLE_TABLE. This method must only be called on those descriptors
* holding an EntityAccessor. NOTE: Inheritance is currently not supported
* on embeddables.
*/
public boolean usesSingleTableInheritanceStrategy() {
return ((EntityAccessor) m_classAccessor).getInheritance().usesSingleTableStrategy();
}
/**
* INTERNAL:
* Return true if this descriptor uses a table per class inheritance policy.
*/
public boolean usesTablePerClassInheritanceStrategy() {
return m_descriptor.hasTablePerClassPolicy();
}
/**
* INTERNAL:
* Return true if this descriptors class processed OptimisticLocking
* meta data of type VERSION_COLUMN.
*/
public boolean usesVersionColumnOptimisticLocking() {
// If an optimistic locking metadata of type VERSION_COLUMN was not
// specified, then m_usesCascadedOptimisticLocking will be null, that
// is, we won't have processed the cascade value.
return m_usesCascadedOptimisticLocking != null;
}
/**
* INTERNAL:
* This method is used to validate derived id fields only. Re-using the
* invalid composite pk attribute validation exception would yield an
* interesting error message. Therefore, this method should be used
* to validate derived id members. When validating derived ids things are
* slightly reversed in terms on context. The expectedType passed in should
* be the boxed type (were applicable).
*/
public void validateDerivedPKClassId(String attributeName, String expectedType, String referenceClassName) {
if (m_pkClassIDs.containsKey(attributeName)) {
String actualType = m_pkClassIDs.get(attributeName);
if (actualType.equals(expectedType)) {
m_pkClassIDs.remove(attributeName);
} else {
throw ValidationException.invalidDerivedCompositePKAttribute(referenceClassName, getPKClassName(), attributeName, expectedType, actualType);
}
}
}
/**
* INTERNAL:
* This method is used only to validate id fields that were found on a
* pk class were also found on the entity. The actualType passed in should
* be the boxed type (were applicable).
*/
public void validatePKClassId(String attributeName, String actualType) {
if (m_pkClassIDs.containsKey(attributeName)) {
String expectedType = m_pkClassIDs.get(attributeName);
if (expectedType.equals(actualType)) {
m_pkClassIDs.remove(attributeName);
} else {
throw ValidationException.invalidCompositePKAttribute(getJavaClassName(), getPKClassName(), attributeName, expectedType, actualType);
}
}
}
}