org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.BasicAccessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction 180e602
/*******************************************************************************
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
* 05/16/2008-1.0M8 Guy Pelletier
* - 218084: Implement metadata merging functionality between mapping files
* 06/20/2008-1.0 Guy Pelletier
* - 232975: Failure when attribute type is generic
* 08/27/2008-1.1 Guy Pelletier
* - 211329: Add sequencing on non-id attribute(s) support to the EclipseLink-ORM.XML Schema
* 09/23/2008-1.1 Guy Pelletier
* - 241651: JPA 2.0 Access Type 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)
* 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
* 10/21/2009-2.0 Guy Pelletier
* - 290567: mappedbyid support incomplete
* 12/2/2009-2.1 Guy Pelletier
* - 296612: Add current annotation only metadata support of return insert/update to the EclipseLink-ORM.XML Schema
* 03/08/2010-2.1 Guy Pelletier
* - 303632: Add attribute-type for mapping attributes to EclipseLink-ORM
* 04/27/2010-2.1 Guy Pelletier
* - 309856: MappedSuperclasses from XML are not being initialized properly
* 07/05/2010-2.1.1 Guy Pelletier
* - 317708: Exception thrown when using LAZY fetch on VIRTUAL mapping
* 03/24/2011-2.3 Guy Pelletier
* - 337323: Multi-tenant with shared schema support (part 1)
* 07/03/2011-2.3.1 Guy Pelletier
* - 348756: m_cascadeOnDelete boolean should be changed to Boolean
* 11/28/2012-2.5 Guy Pelletier
* - 374688: JPA 2.1 Converter support
* 07/16/2013-2.5.1 Guy Pelletier
* - 412384: Applying Converter for parameterized basic-type for joda-time's DateTime does not work
******************************************************************************/
package org.eclipse.persistence.internal.jpa.metadata.accessors.mappings;
import java.util.Collection;
import java.util.Map;
import org.eclipse.persistence.annotations.CacheIndex;
import org.eclipse.persistence.annotations.Index;
import org.eclipse.persistence.annotations.Mutable;
import org.eclipse.persistence.annotations.ReturnInsert;
import org.eclipse.persistence.annotations.ReturnUpdate;
import org.eclipse.persistence.annotations.UuidGenerator;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.jpa.metadata.MetadataDescriptor;
import org.eclipse.persistence.internal.jpa.metadata.MetadataLogger;
import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAccessibleObject;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAnnotation;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataClass;
import org.eclipse.persistence.internal.jpa.metadata.cache.CacheIndexMetadata;
import org.eclipse.persistence.internal.jpa.metadata.columns.ColumnMetadata;
import org.eclipse.persistence.internal.jpa.metadata.converters.EnumeratedMetadata;
import org.eclipse.persistence.internal.jpa.metadata.converters.LobMetadata;
import org.eclipse.persistence.internal.jpa.metadata.mappings.ReturnInsertMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.GeneratedValueMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.SequenceGeneratorMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.TableGeneratorMetadata;
import org.eclipse.persistence.internal.jpa.metadata.sequencing.UuidGeneratorMetadata;
import org.eclipse.persistence.internal.jpa.metadata.tables.IndexMetadata;
import org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappings;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.foundation.AbstractDirectMapping;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_BASIC;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_COLUMN;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_FETCH_EAGER;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_GENERATED_VALUE;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_SEQUENCE_GENERATOR;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_TABLE_GENERATOR;
/**
* INTERNAL:
* A relational accessor. A Basic annotation may or may not be present on the
* accessible object.
*
* Key notes:
* - any metadata mapped from XML to this class must be compared in the
* equals method.
* - any metadata mapped from XML to this class must be handled in the merge
* method. (merging is done at the accessor/mapping level)
* - any metadata mapped from XML to this class must be initialized in the
* initXMLObject method.
* - methods should be preserved in alphabetical order.
*
* @author Guy Pelletier
* @since TopLink EJB 3.0 Reference Implementation
*/
public class BasicAccessor extends DirectAccessor {
private Boolean m_mutable;
private Boolean m_returnUpdate;
private ColumnMetadata m_column;
private DatabaseField m_databaseField;
private GeneratedValueMetadata m_generatedValue;
private ReturnInsertMetadata m_returnInsert;
private SequenceGeneratorMetadata m_sequenceGenerator;
private TableGeneratorMetadata m_tableGenerator;
private UuidGeneratorMetadata m_uuidGenerator;
private IndexMetadata m_index;
private CacheIndexMetadata m_cacheIndex;
/**
* INTERNAL:
* Used for OX mapping.
*/
public BasicAccessor() {
super("");
}
/**
* INTERNAL:
*/
public BasicAccessor(String xmlElement) {
super(xmlElement);
}
/**
* INTERNAL:
*/
public BasicAccessor(MetadataAnnotation annotation, MetadataAccessibleObject accessibleObject, ClassAccessor classAccessor) {
super(annotation, accessibleObject, classAccessor);
// Set the basic metadata if one is present.
MetadataAnnotation basic = getAnnotation(JPA_BASIC);
if (basic != null) {
setFetch(basic.getAttributeString("fetch"));
setOptional(basic.getAttributeBooleanDefaultTrue("optional"));
}
// Set the column metadata if one if present.
m_column = new ColumnMetadata(getAnnotation(JPA_COLUMN), this);
// Set the mutable value if one is present.
if (isAnnotationPresent(Mutable.class)) {
m_mutable = getAnnotation(Mutable.class).getAttributeBooleanDefaultTrue("value");
}
// Set the generated value if one is present.
if (isAnnotationPresent(JPA_GENERATED_VALUE)) {
m_generatedValue = new GeneratedValueMetadata(getAnnotation(JPA_GENERATED_VALUE), this);
}
// Set the sequence generator if one is present.
if (isAnnotationPresent(JPA_SEQUENCE_GENERATOR)) {
m_sequenceGenerator = new SequenceGeneratorMetadata(getAnnotation(JPA_SEQUENCE_GENERATOR), this);
}
// Set the table generator if one is present.
if (isAnnotationPresent(JPA_TABLE_GENERATOR)) {
m_tableGenerator = new TableGeneratorMetadata(getAnnotation(JPA_TABLE_GENERATOR), this);
}
// Set the table generator if one is present.
if (isAnnotationPresent(UuidGenerator.class)) {
m_uuidGenerator = new UuidGeneratorMetadata(getAnnotation(UuidGenerator.class), this);
}
// Set the return insert if one is present.
if (isAnnotationPresent(ReturnInsert.class)) {
m_returnInsert = new ReturnInsertMetadata(getAnnotation(ReturnInsert.class), this);
}
// Set the return update if one is present.
m_returnUpdate = isAnnotationPresent(ReturnUpdate.class);
// Set the index annotation if one is present.
if (isAnnotationPresent(Index.class)) {
m_index = new IndexMetadata(getAnnotation(Index.class), this);
}
// Set the cache index annotation if one is present.
if (isAnnotationPresent(CacheIndex.class)) {
m_cacheIndex = new CacheIndexMetadata(getAnnotation(CacheIndex.class), this);
}
}
/**
* INTERNAL:
*/
@Override
public boolean equals(Object objectToCompare) {
if (super.equals(objectToCompare) && objectToCompare instanceof BasicAccessor) {
BasicAccessor basicAccessor = (BasicAccessor) objectToCompare;
if (! valuesMatch(m_mutable, basicAccessor.getMutable())) {
return false;
}
if (! valuesMatch(m_returnUpdate, basicAccessor.getReturnUpdate())) {
return false;
}
if (! valuesMatch(m_column, basicAccessor.getColumn())) {
return false;
}
if (! valuesMatch(m_generatedValue, basicAccessor.getGeneratedValue())) {
return false;
}
if (! valuesMatch(m_returnInsert, basicAccessor.getReturnInsert())) {
return false;
}
if (! valuesMatch(m_sequenceGenerator, basicAccessor.getSequenceGenerator())) {
return false;
}
if (! valuesMatch(m_uuidGenerator, basicAccessor.getUuidGenerator())) {
return false;
}
return valuesMatch(m_tableGenerator, basicAccessor.getTableGenerator());
}
return false;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public ColumnMetadata getColumn() {
return m_column;
}
/**
* INTERNAL:
* Return the column from xml if there is one, otherwise look for an
* annotation.
*/
protected ColumnMetadata getColumn(String loggingCtx) {
return m_field == null ? (m_column == null ? super.getColumn(loggingCtx) : m_column) : m_field;
}
/**
* INTERNAL:
*/
public String getDefaultFetchType() {
return JPA_FETCH_EAGER;
}
/**
* INTERNAL:
*/
protected DatabaseField getDatabaseField() {
return m_databaseField;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public GeneratedValueMetadata getGeneratedValue() {
return m_generatedValue;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public Boolean getMutable() {
return m_mutable;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public ReturnInsertMetadata getReturnInsert() {
return m_returnInsert;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public Boolean getReturnUpdate() {
return m_returnUpdate;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public SequenceGeneratorMetadata getSequenceGenerator() {
return m_sequenceGenerator;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public TableGeneratorMetadata getTableGenerator() {
return m_tableGenerator;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public UuidGeneratorMetadata getUuidGenerator() {
return m_uuidGenerator;
}
/**
* INTERNAL:
*/
@Override
public void initXMLObject(MetadataAccessibleObject accessibleObject, XMLEntityMappings entityMappings) {
super.initXMLObject(accessibleObject, entityMappings);
// Default a column if necessary.
if (m_column == null) {
m_column = new ColumnMetadata(this);
} else {
// Initialize single objects.
initXMLObject(m_column, accessibleObject);
}
// Initialize single objects.
initXMLObject(m_generatedValue, accessibleObject);
initXMLObject(m_returnInsert, accessibleObject);
initXMLObject(m_sequenceGenerator, accessibleObject);
initXMLObject(m_tableGenerator, accessibleObject);
initXMLObject(m_uuidGenerator, accessibleObject);
}
/**
* INTERNAL:
* Return true if this accessor represents a basic mapping.
*/
@Override
public boolean isBasic() {
return true;
}
/**
* INTERNAL:
* Method to return whether a class is a collection or not.
*/
protected boolean isCollectionClass(MetadataClass cls) {
return cls.extendsInterface(Collection.class);
}
/**
* INTERNAL:
* Method to return whether a class is a map or not.
*/
protected boolean isMapClass(MetadataClass cls) {
return cls.extendsInterface(Map.class);
}
/**
* INTERNAL:
* USed for OX mapping
*/
public Boolean isReturnUpdate() {
return m_returnUpdate != null && m_returnUpdate.booleanValue();
}
/**
* INTERNAL:
* Process a basic accessor.
*/
public void process() {
// Process a DirectToFieldMapping, that is a Basic that could
// be used in conjunction with a Lob, Temporal, Enumerated
// or inferred to be used with a serialized mapping.
AbstractDirectMapping mapping = getOwningDescriptor().getClassDescriptor().newDirectMapping();
setMapping(mapping);
// Process the @Column or column element if there is one.
// A number of methods depend on this field so it must be
// initialized before any further processing can take place.
m_databaseField = getDatabaseField(getDescriptor().getPrimaryTable(), MetadataLogger.COLUMN);
// To resolve any generic types (or respect an attribute type
// specification) we need to set the attribute classification on the
// mapping to ensure we do the right conversions.
if (hasAttributeType() || getAccessibleObject().isGenericType()) {
mapping.setAttributeClassificationName(getReferenceClassName());
}
mapping.setField(m_databaseField);
mapping.setIsReadOnly(m_databaseField.isReadOnly());
mapping.setAttributeName(getAttributeName());
mapping.setIsOptional(isOptional());
mapping.setIsLazy(usesIndirection());
// Will check for PROPERTY access.
setAccessorMethods(mapping);
// Process a converter for this mapping. We will look for an eclipselink
// convert value first. If none is found then we'll look for a JPA
// converter, that is, Convert, Enumerated, Lob and Temporal. With
// everything falling into a serialized mapping if no converter
// whatsoever is found.
processMappingValueConverter(mapping, getConvert(), getConverts(), getReferenceClass(), getReferenceClassWithGenerics());
// Process a mutable setting.
if (m_mutable != null) {
mapping.setIsMutable(m_mutable.booleanValue());
}
// Process the @ReturnInsert and @ReturnUpdate annotations.
processReturnInsertAndUpdate();
// Process a generated value setting.
processGeneratedValue();
// Add the table generator to the project if one is set.
if (m_tableGenerator != null) {
getProject().addTableGenerator(m_tableGenerator, getDescriptor().getDefaultCatalog(), getDescriptor().getDefaultSchema());
}
// Add the sequence generator to the project if one is set.
if (m_sequenceGenerator != null) {
getProject().addSequenceGenerator(m_sequenceGenerator, getDescriptor().getDefaultCatalog(), getDescriptor().getDefaultSchema());
}
// Add the uuid generator to the project if one is set.
if (m_uuidGenerator != null) {
getProject().addUuidGenerator(m_uuidGenerator);
}
// Process the index metadata.
processIndex();
processCacheIndex();
}
/**
* INTERNAL:
* Process an Enumerated annotation. The method may still be called if no
* Enumerated annotation has been specified but the accessor's reference
* class is a valid enumerated type.
*/
@Override
protected void processEnumerated(EnumeratedMetadata enumerated, DatabaseMapping mapping, MetadataClass referenceClass, boolean isForMapKey) {
// If the raw class is a collection or map (with generics or not), we
// don't want to put a TypeConversionConverter on the mapping. Instead,
// we will want a serialized converter. For example, we could have
// an EnumSet relation type.
if (isCollectionClass(referenceClass) || isMapClass(referenceClass)) {
processSerialized(mapping, referenceClass, isForMapKey);
} else {
super.processEnumerated(enumerated, mapping, referenceClass, isForMapKey);
}
}
/**
* INTERNAL:
* Process the generated value metadata.
*/
protected void processGeneratedValue() {
if (m_generatedValue != null) {
// Set the sequence number field on all the owning descriptors.
for (MetadataDescriptor owningDescriptor : getOwningDescriptors()) {
DatabaseField existingSequenceNumberField = owningDescriptor.getSequenceNumberField();
if (existingSequenceNumberField == null) {
owningDescriptor.setSequenceNumberField(m_databaseField);
getProject().addGeneratedValue(m_generatedValue, owningDescriptor.getJavaClass());
} else {
throw ValidationException.onlyOneGeneratedValueIsAllowed(owningDescriptor.getJavaClass(), existingSequenceNumberField.getQualifiedName(), m_databaseField.getQualifiedName());
}
}
}
}
/**
* INTERNAL:
* Process index information for the given mapping.
*/
protected void processIndex() {
if (m_index != null) {
m_index.process(getDescriptor(), m_databaseField.getName());
}
}
/**
* INTERNAL:
* Process cache index.
*/
protected void processCacheIndex() {
if (m_cacheIndex != null) {
m_cacheIndex.process(getDescriptor(), m_databaseField.getName());
}
}
/**
* INTERNAL:
* Process a Lob metadata. The lob must be specified to process and
* create a lob type mapping.
*/
@Override
protected void processLob(LobMetadata lob, DatabaseMapping mapping, MetadataClass referenceClass, boolean isForMapKey) {
// If the raw class is a collection or map (with generics or not), we
// don't want to put a TypeConversionConverter on the mapping. Instead,
// we will want a serialized converter.
if (isCollectionClass(referenceClass) || isMapClass(referenceClass)) {
processSerialized(mapping, referenceClass, getMetadataClass(java.sql.Blob.class), isForMapKey);
} else {
super.processLob(lob, mapping, referenceClass, isForMapKey);
}
}
/**
* INTERNAL:
* Process a ReturnInsert annotation.
*/
@Override
protected void processReturnInsert() {
if (m_returnInsert != null) {
m_returnInsert.process(getDescriptor(), m_databaseField);
}
}
/**
* INTERNAL:
* Process a return update setting.
*/
@Override
protected void processReturnUpdate() {
if (isReturnUpdate()) {
getDescriptor().addFieldForUpdate(m_databaseField);
}
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public IndexMetadata getIndex() {
return m_index;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setIndex(IndexMetadata index) {
m_index = index;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public CacheIndexMetadata getCacheIndex() {
return m_cacheIndex;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setCacheIndex(CacheIndexMetadata index) {
m_cacheIndex = index;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setColumn(ColumnMetadata column) {
m_column = column;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setGeneratedValue(GeneratedValueMetadata value) {
m_generatedValue = value;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setMutable(Boolean mutable) {
m_mutable = mutable;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setReturnInsert(ReturnInsertMetadata returnInsert) {
m_returnInsert = returnInsert;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setReturnUpdate(Boolean returnUpdate) {
m_returnUpdate = returnUpdate;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setSequenceGenerator(SequenceGeneratorMetadata sequenceGenerator) {
m_sequenceGenerator = sequenceGenerator;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setTableGenerator(TableGeneratorMetadata tableGenerator) {
m_tableGenerator = tableGenerator;
}
/**
* INTERNAL:
* Used for OX mapping.
*/
public void setUuidGenerator(UuidGeneratorMetadata uuidGenerator) {
m_uuidGenerator = uuidGenerator;
}
}