| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 1998, 2018 IBM Corporation. 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 |
| // 12/17/2010-2.2 Guy Pelletier |
| // - 330755: Nested embeddables can't be used as embedded ids |
| // 11/10/2011-2.4 Guy Pelletier |
| // - 357474: Address primaryKey option from tenant discriminator column |
| // 14/05/2012-2.4 Guy Pelletier |
| // - 376603: Provide for table per tenant support for multitenant applications |
| // 03/23/2016-2.6_WAS Will Dazey |
| // - 490114: Add support for PersistenceUnitUtil.getIdentifier with nested embeddables in EmbeddedId class |
| package org.eclipse.persistence.descriptors; |
| |
| import java.io.Serializable; |
| import java.security.AccessController; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.persistence.annotations.CacheKeyType; |
| import org.eclipse.persistence.exceptions.DescriptorException; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.internal.descriptors.ObjectBuilder; |
| import org.eclipse.persistence.internal.helper.DatabaseField; |
| import org.eclipse.persistence.internal.identitymaps.CacheId; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.mappings.ObjectReferenceMapping; |
| import org.eclipse.persistence.mappings.converters.Converter; |
| import org.eclipse.persistence.mappings.foundation.AbstractColumnMapping; |
| import org.eclipse.persistence.queries.UpdateObjectQuery; |
| |
| /** |
| * <p> |
| * <b>Description</b>: Place holder for CMP specific information. This class can be set on the ClassDescriptor. |
| * |
| * @see org.eclipse.persistence.descriptors.PessimisticLockingPolicy |
| * |
| * @since TopLink 10.1.3 |
| */ |
| public class CMPPolicy implements java.io.Serializable, Cloneable { |
| |
| protected Boolean forceUpdate; |
| protected Boolean updateAllFields; |
| |
| /** Allow the bean to always be locked as it enters a new transaction. */ |
| protected PessimisticLockingPolicy pessimisticLockingPolicy; |
| |
| |
| /** Class originally mapped, before anything was generated. */ |
| protected Class<?> mappedClass; |
| protected ClassDescriptor descriptor; |
| |
| /** The object deferral level. This controls when objects changes will be sent to the Database. */ |
| protected int modificationDeferralLevel = ALL_MODIFICATIONS; |
| |
| /** defer no changes */ |
| public static final int NONE = 0; |
| |
| /** defer updates */ |
| public static final int UPDATE_MODIFICATIONS = 1; |
| |
| /** defer all modifications, inserts and deletes included (default) */ |
| public static final int ALL_MODIFICATIONS = 2; |
| |
| /** This setting will allow customers to control when Toplink will issue the insert SQL for CMP beans. */ |
| protected int nonDeferredCreateTime = UNDEFINED; |
| |
| /** undefined if it is non-deferred issue sql at create */ |
| public static final int UNDEFINED = 0; |
| |
| /** issue SQL after ejbCreate but before ejbPostCreate */ |
| public static final int AFTER_EJBCREATE = 1; |
| |
| /** issue SQL after ejbPostCreate */ |
| public static final int AFTER_EJBPOSTCREATE = 2; |
| |
| public CMPPolicy() { |
| this.forceUpdate = null; |
| this.updateAllFields = null; |
| } |
| |
| /** |
| * ADVANCED: |
| * This setting is only available for CMP beans that are not being deferred. |
| * Using it will allow TopLink to determine if the INSERT SQL should be sent to |
| * the database before or after the postCreate call. |
| */ |
| public int getNonDeferredCreateTime() { |
| return this.nonDeferredCreateTime; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the policy for bean pessimistic locking |
| * @see org.eclipse.persistence.descriptors.PessimisticLockingPolicy |
| */ |
| public PessimisticLockingPolicy getPessimisticLockingPolicy() { |
| return pessimisticLockingPolicy; |
| } |
| |
| /** |
| * ADVANCED: |
| * This can be set to control when changes to objects are submitted to the database |
| * This is only applicable to TopLink's CMP implementation and not available within |
| * the core. |
| */ |
| public void setDeferModificationsUntilCommit(int deferralLevel) { |
| this.modificationDeferralLevel = deferralLevel; |
| } |
| |
| /** |
| * PUBLIC: |
| * Define the mapped class. This is the class which was originally mapped in the MW |
| * |
| */ |
| public void setMappedClass(Class<?> newMappedClass) { |
| mappedClass = newMappedClass; |
| } |
| |
| /** |
| * PUBLIC: |
| * Answer the mapped class. This is the class which was originally mapped in the MW |
| * |
| */ |
| public Class<?> getMappedClass() { |
| return mappedClass; |
| } |
| |
| /** |
| * ADVANCED: |
| * This setting is only available for CMP beans that are not being deferred. |
| * Using it will allow TopLink to determine if the INSERT SQL should be sent to |
| * the database before or after the postCreate call. |
| */ |
| public void setNonDeferredCreateTime(int createTime) { |
| this.nonDeferredCreateTime = createTime; |
| } |
| |
| /** |
| * PUBLIC: |
| * Configure bean pessimistic locking |
| * |
| * @see org.eclipse.persistence.descriptors.PessimisticLockingPolicy |
| */ |
| public void setPessimisticLockingPolicy(PessimisticLockingPolicy policy) { |
| pessimisticLockingPolicy = policy; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return true if bean pessimistic locking is configured |
| */ |
| public boolean hasPessimisticLockingPolicy() { |
| return pessimisticLockingPolicy != null; |
| } |
| |
| /** |
| * ADVANCED: |
| * This can be used to control when changes to objects are submitted to the database |
| * This is only applicable to TopLink's CMP implementation and not available within |
| * the core. |
| */ |
| public int getDeferModificationsUntilCommit() { |
| return this.modificationDeferralLevel; |
| } |
| |
| /** |
| * ADVANCED: |
| * Return true if descriptor is set to always update all registered objects of this type |
| */ |
| public boolean getForceUpdate() { |
| // default to false |
| return (Boolean.TRUE.equals(this.forceUpdate)); |
| } |
| |
| /** |
| * ADVANCED: |
| * Configure whether TopLink should always update all registered objects of |
| * this type. NOTE: if set to true, then updateAllFields must also be set |
| * to true |
| * |
| */ |
| public void setForceUpdate(boolean shouldForceUpdate) { |
| this.forceUpdate = shouldForceUpdate; |
| } |
| |
| /** |
| * ADVANCED: |
| * Return true if descriptor is set to update all fields for an object of this |
| * type when an update occurs. |
| */ |
| public boolean getUpdateAllFields() { |
| // default to false |
| return Boolean.TRUE.equals(this.updateAllFields); |
| } |
| |
| /** |
| * ADVANCED: |
| * Configure whether TopLink should update all fields for an object of this |
| * type when an update occurs. |
| * |
| */ |
| public void setUpdateAllFields(boolean shouldUpdatAllFields) { |
| this.updateAllFields = shouldUpdatAllFields; |
| } |
| |
| /** |
| * INTERNAL: |
| * return internal tri-state value so we can decide whether to inherit or not at init time. |
| */ |
| public Boolean internalGetForceUpdate() { |
| return this.forceUpdate; |
| } |
| |
| /** |
| * INTERNAL: |
| * return internal tri-state value so we can decide whether to inherit or not at init time. |
| */ |
| public Boolean internalGetUpdateAllFields() { |
| return this.updateAllFields; |
| } |
| |
| /** |
| * INTERNAL: |
| * internal method to set the tri-state value. This is done in InheritancePolicy at init time. |
| */ |
| public void internalSetForceUpdate(Boolean newForceUpdateValue) { |
| this.forceUpdate = newForceUpdateValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * internal method to set the tri-state value. This is done in InheritancePolicy at init time. |
| */ |
| public void internalSetUpdateAllFields(Boolean newUpdateAllFieldsValue) { |
| this.updateAllFields = newUpdateAllFieldsValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * Initialize the CMPPolicy settings. |
| */ |
| public void initialize(ClassDescriptor descriptor, AbstractSession session) throws DescriptorException { |
| // updateAllFields is true so set custom query in DescriptorQueryManager |
| // to force full SQL. Don't overwrite a user defined query |
| if (this.getUpdateAllFields() && !descriptor.getQueryManager().hasUpdateQuery()) { |
| descriptor.getQueryManager().setUpdateQuery(new UpdateObjectQuery()); |
| } |
| |
| // make sure updateAllFields is set if forceUpdate is true |
| if (this.getForceUpdate() && !this.getUpdateAllFields()) { |
| throw DescriptorException.updateAllFieldsNotSet(descriptor); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Initialize the CMPPolicy settings for remote sessions. |
| */ |
| public void remoteInitialize(ClassDescriptor descriptor, AbstractSession session) throws DescriptorException { |
| } |
| |
| /** |
| * INTERNAL: |
| * @return Returns the owningDescriptor. |
| */ |
| public ClassDescriptor getDescriptor() { |
| return descriptor; |
| } |
| |
| /** |
| * INTERNAL: |
| * @param owningDescriptor The owningDescriptor to set. |
| */ |
| public void setDescriptor(ClassDescriptor owningDescriptor) { |
| this.descriptor = owningDescriptor; |
| } |
| |
| /** |
| * INTERNAL: |
| * Recursive method to set a field value in the given key instance. |
| */ |
| protected void setFieldValue(KeyElementAccessor accessor, Object keyInstance, DatabaseMapping mapping, AbstractSession session, int[] elementIndex, Object ... keyElements) { |
| if (mapping.isAggregateMapping()) { |
| Object nestedObject = mapping.getRealAttributeValueFromObject(keyInstance, session); |
| |
| if (nestedObject == null) { |
| nestedObject = getClassInstance(mapping.getReferenceDescriptor().getJavaClass()); |
| mapping.setRealAttributeValueInObject(keyInstance, nestedObject); |
| } |
| |
| // keep drilling down the nested mappings ... |
| setFieldValue(accessor, nestedObject, mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(accessor.getDatabaseField()), session, elementIndex, keyElements); |
| } else { |
| Object fieldValue = null; |
| |
| if (mapping.isAbstractColumnMapping()) { |
| fieldValue = keyElements[elementIndex[0]]; |
| Converter converter = ((AbstractColumnMapping) mapping).getConverter(); |
| if (converter != null){ |
| fieldValue = converter.convertDataValueToObjectValue(fieldValue, session); |
| } |
| ++elementIndex[0]; |
| } else if (mapping.isObjectReferenceMapping()) { |
| // what if mapping comes from derived ID. need to get the derived mapping. |
| // get reference descriptor and extract pk from target cmp policy |
| fieldValue = mapping.getReferenceDescriptor().getCMPPolicy().createPrimaryKeyInstanceFromPrimaryKeyValues(session, elementIndex, keyElements); |
| } |
| |
| accessor.setValue(keyInstance, fieldValue); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if this policy is for CMP3. |
| */ |
| public boolean isCMP3Policy() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Clone the CMPPolicy |
| */ |
| @Override |
| public CMPPolicy clone() { |
| try { |
| return (CMPPolicy) super.clone(); |
| } catch (CloneNotSupportedException exception) { |
| throw new InternalError(exception.getMessage()); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Convert all the class-name-based settings in this object to actual class-based |
| * settings. This method is used when converting a project that has been built |
| * with class names to a project with classes. |
| */ |
| public void convertClassNamesToClasses(ClassLoader classLoader){ |
| } |
| |
| /** |
| * INTERNAL: |
| * Create an instance of the composite primary key class for the key object. |
| */ |
| public Object createPrimaryKeyInstanceFromId(Object key, AbstractSession session) { |
| if (this.descriptor.getCachePolicy().getCacheKeyType() == CacheKeyType.CACHE_ID) { |
| return createPrimaryKeyInstanceFromPrimaryKeyValues(session, new int[]{0}, ((CacheId)key).getPrimaryKey()); |
| } else { |
| return createPrimaryKeyInstanceFromPrimaryKeyValues(session, new int[]{0}, key); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Create an instance of the composite primary key class for the key object. |
| * Yes the elementIndex looks strange but this is just a simple way to get the index to be pass-by-reference |
| */ |
| public Object createPrimaryKeyInstanceFromPrimaryKeyValues(AbstractSession session, int[] elementIndex, Object ... keyElements ) { |
| Object keyInstance = null; |
| KeyElementAccessor[] pkElementArray = getKeyClassFields(); |
| if (isSingleKey(pkElementArray)) { |
| for (KeyElementAccessor accessor: pkElementArray){ |
| DatabaseMapping mapping = getDescriptor().getObjectBuilder().getMappingForAttributeName(accessor.getAttributeName()); |
| if (mapping != null && !mapping.isMultitenantPrimaryKeyMapping()){ |
| if (mapping.isAbstractColumnMapping()) { |
| Converter converter = ((AbstractColumnMapping) mapping).getConverter(); |
| if (converter != null){ |
| return converter.convertDataValueToObjectValue(keyElements[elementIndex[0]], session); |
| } |
| keyInstance = keyElements[elementIndex[0]]; |
| } else if (mapping.isObjectReferenceMapping()) { // what if mapping comes from derived ID. need to get the derived mapping. |
| //get reference descriptor and extract pk from target cmp policy |
| keyInstance = mapping.getReferenceDescriptor().getCMPPolicy().createPrimaryKeyInstanceFromPrimaryKeyValues(session, elementIndex, keyElements); |
| } |
| ++elementIndex[0]; // remove processed key in case keys are complex and derived |
| } |
| if (keyInstance != null){ |
| return keyInstance; |
| } |
| } |
| } else { |
| keyInstance = getPKClassInstance(); |
| ObjectBuilder objectBuilder = getDescriptor().getObjectBuilder(); |
| //get clone of Key so we can remove values. |
| for (int index = 0; index < pkElementArray.length; index++) { |
| KeyElementAccessor accessor = pkElementArray[index]; |
| DatabaseMapping mapping = getDescriptor().getObjectBuilder().getMappingForAttributeName(accessor.getAttributeName()); |
| if (mapping == null) { |
| mapping = objectBuilder.getMappingForField(accessor.getDatabaseField()); |
| if (! mapping.isAggregateObjectMapping() && ! mapping.isAbstractDirectMapping()) { |
| // Found a mapping for the database field but it's not an aggregate (embedded ID) or a direct mapping so maybe the mappings |
| // have been mapped multiple times. Check read-only mappings for dtf or aggregate |
| List<DatabaseMapping> readOnlyMappings = objectBuilder.getReadOnlyMappingsForField(accessor.getDatabaseField()); |
| for (DatabaseMapping readOnlyMapping : readOnlyMappings) { |
| if (readOnlyMapping.isAggregateObjectMapping() || readOnlyMapping.isDirectToFieldMapping()) { |
| mapping = readOnlyMapping; |
| break; |
| } |
| } |
| |
| } |
| } |
| |
| if (accessor.isNestedAccessor()) { |
| // Need to recursively build all the nested objects. |
| setFieldValue(accessor, keyInstance, mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(accessor.getDatabaseField()), session, elementIndex, keyElements); |
| } else { |
| // Not nested but may be a single layer aggregate so check. |
| if (mapping.isAggregateMapping()) { |
| DatabaseMapping nestedMapping = mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(accessor.getDatabaseField()); |
| if (nestedMapping == null) { |
| //must be a read only mapping |
| List<DatabaseMapping> readOnlyMappings = mapping.getReferenceDescriptor().getObjectBuilder().getReadOnlyMappingsForField(accessor.getDatabaseField()); |
| for (DatabaseMapping readOnlyMapping : readOnlyMappings) { |
| if (readOnlyMapping.isAbstractDirectMapping()) { |
| mapping = readOnlyMapping; |
| break; |
| } |
| } |
| } else { |
| mapping = nestedMapping; |
| } |
| } |
| |
| setFieldValue(accessor, keyInstance, mapping, session, elementIndex, keyElements); |
| } |
| } |
| } |
| |
| return keyInstance; |
| } |
| |
| /** |
| * INTERNAL: |
| * Create an instance of the Id class or value from the object. |
| */ |
| public Object createPrimaryKeyInstance(Object object, AbstractSession session) { |
| KeyElementAccessor[] pkElementArray = this.getKeyClassFields(); |
| ObjectBuilder builder = getDescriptor().getObjectBuilder(); |
| if (pkElementArray.length == 1 && pkElementArray[0] instanceof KeyIsElementAccessor){ |
| DatabaseMapping mapping = builder.getMappingForAttributeName(pkElementArray[0].getAttributeName()); |
| Object fieldValue = mapping.getRealAttributeValueFromObject(object, session); |
| if (mapping.isObjectReferenceMapping()){ |
| fieldValue = mapping.getReferenceDescriptor().getCMPPolicy().createPrimaryKeyInstance(fieldValue, session); |
| } |
| return fieldValue; |
| } |
| |
| Object keyInstance = getPKClassInstance(); |
| Set<ObjectReferenceMapping> usedObjectReferenceMappings = new HashSet<>(); |
| for (int index = 0; index < pkElementArray.length; index++) { |
| Object keyObj = object; |
| KeyElementAccessor accessor = pkElementArray[index]; |
| DatabaseField field = accessor.getDatabaseField(); |
| DatabaseMapping mapping = builder.getMappingForField(field); |
| Object nestedKeyInstance = keyInstance; |
| // With session validation, the mapping shouldn't be null at this |
| // point, don't bother checking. |
| if (!mapping.isObjectReferenceMapping() || !usedObjectReferenceMappings.contains(mapping)){ |
| while (mapping.isAggregateObjectMapping()) { |
| keyObj = mapping.getRealAttributeValueFromObject(keyObj, session); |
| mapping = mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(field); |
| |
| //Check for embedded Id values |
| if (mapping.isAggregateMapping()) { |
| Object nestedObject = mapping.getRealAttributeValueFromObject(nestedKeyInstance, session); |
| if (nestedObject == null) { |
| nestedObject = getClassInstance(mapping.getReferenceDescriptor().getJavaClass()); |
| } |
| mapping.setRealAttributeValueInObject(nestedKeyInstance, nestedObject); |
| nestedKeyInstance = nestedObject; |
| } |
| } |
| Object fieldValue = mapping.getRealAttributeValueFromObject(keyObj, session); |
| if (mapping.isObjectReferenceMapping()){ |
| fieldValue = mapping.getReferenceDescriptor().getCMPPolicy().createPrimaryKeyInstance(fieldValue, session); |
| usedObjectReferenceMappings.add((ObjectReferenceMapping)mapping); |
| } |
| accessor.setValue(nestedKeyInstance, fieldValue); |
| } |
| } |
| |
| return keyInstance; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return a new instance of the class provided. |
| */ |
| public Object getClassInstance(Class<?> cls) { |
| if (cls != null){ |
| try { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass<>(cls)); |
| } else { |
| return org.eclipse.persistence.internal.security.PrivilegedAccessHelper.newInstanceFromClass(cls); |
| } |
| } catch (Exception e) { |
| throw ValidationException.reflectiveExceptionWhileCreatingClassInstance(cls.getName(), e); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public <T> T getPKClassInstance() { |
| // TODO fix this exception so that it is more descriptive |
| // This method only works in CMP3Policy but was added here for separation |
| // of components |
| throw new RuntimeException("Should not get here."); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public <T> Class<T> getPKClass() { |
| // TODO fix this exception so that it is more descriptive |
| // This method only works in CMP3Policy but was added here for separation |
| // of components |
| throw new RuntimeException("Should not get here."); |
| } |
| |
| /** |
| * INTERNAL: |
| * Use the key to create a EclipseLink primary key. |
| * If the key is simple (direct mapped) then just add it to a vector, |
| * otherwise must go through the inefficient process of copying the key into the bean |
| * and extracting the key from the bean. |
| */ |
| public Object createPrimaryKeyFromId(Object key, AbstractSession session) { |
| // TODO fix this exception so that it is more descriptive |
| // This method only works in CMP3Policy but was added here for separation |
| // of components |
| throw new RuntimeException("Should not get here."); |
| } |
| |
| /** |
| * INTERNAL: |
| * Use the key to create a bean and initialize its primary key fields. |
| * Note: If is a compound PK then a primary key object is being used. |
| * This method should only be used for 'templates' when executing |
| * queries. The bean built will not be given an EntityContext and should |
| * not be used as an actual entity bean. |
| * |
| * @param key Object the primary key to use for initializing the bean's |
| * corresponding pk fields |
| * @return Object |
| */ |
| public Object createBeanUsingKey(Object key, AbstractSession session) { |
| // TODO fix this exception so that it is more descriptive |
| // This method only works in CMP3Policy but was added here for separation |
| // of components |
| throw new RuntimeException("Should not get here."); |
| } |
| |
| /** |
| * INTERNAL: |
| * @return Returns the keyClassFields. |
| */ |
| protected KeyElementAccessor[] getKeyClassFields() { |
| // TODO fix this exception so that it is more descriptive |
| // This method only works in CMP3Policy but was added here for separation |
| // of components |
| throw new RuntimeException("Should not get here."); |
| } |
| |
| /** |
| * Check to see if there is a single key element. Iterate through the list of primary key elements |
| * and count only keys that are not part of the Multitenant identifier. |
| * |
| */ |
| protected boolean isSingleKey(KeyElementAccessor[] pkElementArray){ |
| if ((pkElementArray.length == 1) && (pkElementArray[0] instanceof KeyIsElementAccessor)) { |
| return true; |
| } |
| boolean foundFirstElement = false; |
| for (KeyElementAccessor accessor: pkElementArray){ |
| if (!(accessor instanceof KeyIsElementAccessor)){ |
| return false; |
| } |
| if (!accessor.getMapping().isMultitenantPrimaryKeyMapping()){ |
| if (foundFirstElement){ |
| return false; |
| } |
| foundFirstElement = true; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * This is the interface used to encapsulate the the type of key class element |
| */ |
| protected interface KeyElementAccessor { |
| String getAttributeName(); |
| DatabaseField getDatabaseField(); |
| DatabaseMapping getMapping(); |
| Object getValue(Object object, AbstractSession session); |
| void setValue(Object object, Object value); |
| boolean isNestedAccessor(); |
| } |
| |
| /** |
| * INTERNAL: |
| * This class will be used when the keyClass is a primitive |
| */ |
| protected static final class KeyIsElementAccessor implements KeyElementAccessor, Serializable { |
| protected String attributeName; |
| protected DatabaseField databaseField; |
| protected DatabaseMapping mapping; |
| |
| public KeyIsElementAccessor(String attributeName, DatabaseField databaseField, DatabaseMapping mapping) { |
| this.attributeName = attributeName; |
| this.databaseField = databaseField; |
| this.mapping = mapping; |
| } |
| |
| @Override |
| public String getAttributeName() { |
| return attributeName; |
| } |
| |
| @Override |
| public DatabaseField getDatabaseField() { |
| return this.databaseField; |
| } |
| |
| @Override |
| public DatabaseMapping getMapping(){ |
| return this.mapping; |
| } |
| |
| @Override |
| public Object getValue(Object object, AbstractSession session) { |
| return object; |
| } |
| |
| @Override |
| public boolean isNestedAccessor() { |
| return false; |
| } |
| |
| @Override |
| public void setValue(Object object, Object value) { |
| // WIP - do nothing for now??? |
| } |
| } |
| } |