| /* |
| * 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); |
| } |
| } |
| } |
| } |