org.eclipse.persistence.mappings.foundation.AbstractColumnMapping 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 f2b9fc5
/*
* Copyright (c) 1998, 2018 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
// 11/13/2009-2.0 mobrien - 294765: MapKey keyType DirectToField processing
// should return attributeClassification class in getMapKeyTargetType when
// accessor.attributeField is null in the absence of a MapKey annotation
// 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
// 06/03/2013-2.5.1 Guy Pelletier
// - 402380: 3 jpa21/advanced tests failed on server with
// "java.lang.NoClassDefFoundError: org/eclipse/persistence/testing/models/jpa21/advanced/enums/Gender"
package org.eclipse.persistence.mappings.foundation;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.*;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.descriptors.DescriptorIterator;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.remote.DistributedSession;
/**
* Purpose: Maps an attribute or some other property to the corresponding
* database field type. The list of field types that are supported by
* EclipseLink's direct to field mapping is dependent on the relational database
* being used.
*
* @see org.eclipse.persistence.mappings.foundation.AbstractDirectMapping
* @see org.eclipse.persistence.mappings.MultitenantPrimaryKeyMapping
*
* @author Guy Pelletier
* @since TopLink/Java 1.0
*/
public abstract class AbstractColumnMapping extends DatabaseMapping {
/** DatabaseField which this mapping represents. */
protected DatabaseField field;
/** Allows user defined conversion between the object attribute value and the database value. */
protected Converter converter;
protected String converterClassName;
/** Flag to support insertable JPA setting */
protected boolean isInsertable = true;
/** Flag to support updatable JPA setting */
protected boolean isUpdatable = true;
/**
* Default constructor.
*/
public AbstractColumnMapping() {
super();
this.setWeight(WEIGHT_DIRECT);
}
/**
* INTERNAL:
* Cascade perform delete through mappings that require the cascade.
*/
public void cascadePerformRemoveIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) {
// objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* Cascade registerNew for Create through mappings that require the cascade.
*/
public void cascadeRegisterNewIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) {
// objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* The mapping clones itself to create deep copy.
*/
@Override
public Object clone() {
AbstractColumnMapping clone = (AbstractColumnMapping)super.clone();
// Field must be cloned so aggregates do not share fields.
clone.setField(getField().clone());
return clone;
}
/**
* Returns the field this mapping represents.
*/
@Override
protected Vector collectFields() {
Vector databaseField = new Vector(1);
databaseField.addElement(field);
return databaseField;
}
/**
* INTERNAL:
* Convert all the class-name-based settings in this mapping to actual class-based settings
* This method is implemented by subclasses as necessary.
*/
@Override
public void convertClassNamesToClasses(ClassLoader classLoader){
super.convertClassNamesToClasses(classLoader);
// Field may have a type name that needs to be initialize.
if (field != null) {
field.convertClassNamesToClasses(classLoader);
}
// Convert and any Converter class names.
convertConverterClassNamesToClasses(converter, classLoader);
// Instantiate any custom converter class
if (converterClassName != null) {
Class converterClass;
Converter converter;
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
converterClass = AccessController.doPrivileged(new PrivilegedClassForName(converterClassName, true, classLoader));
} catch (PrivilegedActionException exception) {
throw ValidationException.classNotFoundWhileConvertingClassNames(converterClassName, exception.getException());
}
try {
converter = (Converter)AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(converterClass));
} catch (PrivilegedActionException exception) {
throw ValidationException.classNotFoundWhileConvertingClassNames(converterClassName, exception.getException());
}
} else {
converterClass = PrivilegedAccessHelper.getClassForName(converterClassName, true, classLoader);
converter = (Converter)PrivilegedAccessHelper.newInstanceFromClass(converterClass);
}
} catch (ClassNotFoundException exc) {
throw ValidationException.classNotFoundWhileConvertingClassNames(converterClassName, exc);
} catch (Exception e) {
// Catches IllegalAccessException and InstantiationException
throw ValidationException.classNotFoundWhileConvertingClassNames(converterClassName, e);
}
setConverter(converter);
}
}
/**
* INTERNAL:
* An object has been serialized from the server to the client.
* Replace the transient attributes of the remote value holders
* with client-side objects.
*/
@Override
public void fixObjectReferences(Object object, Map objectDescriptors, Map processedObjects, ObjectLevelReadQuery query, DistributedSession session) {
}
/**
* PUBLIC:
* Return the converter on the mapping.
* A converter can be used to convert between the object's value and database value of the attribute.
*/
public Converter getConverter() {
return converter;
}
/**
* INTERNAL:
* Returns the field which this mapping represents.
*/
public DatabaseField getField() {
return field;
}
/**
* INTERNAL:
* Convert the object (attribute or property) value to a field value.
*/
public abstract Object getFieldValue(Object objectValue, AbstractSession session);
/**
* INTERNAL:
* Allows for subclasses to convert the the attribute or property value.
*/
public abstract Object getObjectValue(Object fieldValue, Session session);
/**
* Indicates if the mapping has a converter set on it.
*
* @return true if there is a converter set on the mapping,
* false otherwise.
*/
public boolean hasConverter() {
return converter != null;
}
/**
* INTERNAL:
*/
@Override
public boolean isAbstractColumnMapping() {
return true;
}
/**
* INTERNAL:
* Return true if this mapping is insertable.
*/
protected boolean isInsertable() {
return isInsertable;
}
/**
* INTERNAL:
* Return true if this mapping is updatable.
*/
protected boolean isUpdatable() {
return isUpdatable;
}
/**
* INTERNAL:
* Iterate on the appropriate attribute.
*/
@Override
public void iterate(DescriptorIterator iterator) {
// PERF: Only iterate when required.
if (iterator.shouldIterateOnPrimitives()) {
iterator.iteratePrimitiveForMapping(getAttributeValueFromObject(iterator.getVisitedParent()), this);
}
}
/**
* PUBLIC:
* Set the converter on the mapping.
* A converter can be used to convert between the object's value and database value of the attribute.
*/
public void setConverter(Converter converter) {
this.converter = converter;
}
/**
* PUBLIC:
* Set the converter class name on the mapping. It will be instantiated
* during the convertClassNamesToClasses.
* A converter can be used to convert between the object's value and
* database value of the attribute.
*/
public void setConverterClassName(String converterClassName) {
this.converterClassName = converterClassName;
}
/**
* ADVANCED:
* Set the field in the mapping.
* This can be used for advanced field types, such as XML nodes, or to set the field type.
*/
public void setField(DatabaseField theField) {
field = theField;
}
/**
* INTERNAL:
*/
@Override
public String toString() {
return getClass().getName() + "[" + getAttributeName() + "-->" + getField() + "]";
}
/**
* INTERNAL:
*/
protected abstract void writeValueIntoRow(AbstractRecord row, DatabaseField field, Object value);
}