| /* |
| * 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 |
| // 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; |
| |
| /** |
| * <b>Purpose</b>: 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. |
| */ |
| protected AbstractColumnMapping() { |
| super(); |
| this.setWeight(WEIGHT_DIRECT); |
| } |
| |
| /** |
| * INTERNAL: |
| * Cascade perform delete through mappings that require the cascade. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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<DatabaseField> 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. |
| */ |
| @Override |
| 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); |
| } |