| /* |
| * Copyright (c) 1998, 2020 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 |
| package org.eclipse.persistence.internal.descriptors; |
| |
| import java.lang.reflect.Field; |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| |
| import org.eclipse.persistence.exceptions.DescriptorException; |
| import org.eclipse.persistence.internal.helper.ConversionManager; |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedGetValueFromField; |
| import org.eclipse.persistence.internal.security.PrivilegedSetValueInField; |
| import org.eclipse.persistence.mappings.AttributeAccessor; |
| |
| /** |
| * <p><b>Purpose</b>: A wrapper class for handling cases when the domain object has instance variable |
| * to map to the database field. |
| * |
| * @author Sati |
| * @since TOPLink/Java 1.0 |
| */ |
| public class InstanceVariableAttributeAccessor extends AttributeAccessor { |
| |
| /** The attribute name of an object is converted to Field type to access it reflectively */ |
| protected transient Field attributeField; |
| |
| /** |
| * Returns the class type of the attribute. |
| */ |
| @Override |
| public Class getAttributeClass() { |
| if (getAttributeField() == null) { |
| return null; |
| } |
| |
| return getAttributeType(); |
| } |
| |
| /** |
| * Returns the value of attributeField. |
| * 266912: For Metamodel API - change visibility from protected |
| */ |
| public Field getAttributeField() { |
| return attributeField; |
| } |
| |
| /** |
| * Returns the declared type of attributeField. |
| */ |
| public Class getAttributeType() { |
| return attributeField.getType(); |
| } |
| |
| /** |
| * Returns the value of the attribute on the specified object. |
| */ |
| @Override |
| public Object getAttributeValueFromObject(Object anObject) throws DescriptorException { |
| try { |
| // PERF: Direct variable access. |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| return AccessController.doPrivileged(new PrivilegedGetValueFromField(this.attributeField, anObject)); |
| } catch (PrivilegedActionException exception) { |
| throw DescriptorException.illegalAccesstWhileGettingValueThruInstanceVaraibleAccessor(getAttributeName(), anObject.getClass().getName(), exception.getException()); |
| } |
| } else { |
| // PERF: Direct-var access. |
| return this.attributeField.get(anObject); |
| } |
| } catch (IllegalArgumentException exception) { |
| throw DescriptorException.illegalArgumentWhileGettingValueThruInstanceVariableAccessor(getAttributeName(), getAttributeType().getName(), anObject.getClass().getName(), exception); |
| } catch (IllegalAccessException exception) { |
| throw DescriptorException.illegalAccesstWhileGettingValueThruInstanceVaraibleAccessor(getAttributeName(), anObject.getClass().getName(), exception); |
| } catch (NullPointerException exception) { |
| String className = null; |
| if (anObject != null) { |
| // Some JVM's throw this exception for some very odd reason |
| className = anObject.getClass().getName(); |
| } |
| throw DescriptorException.nullPointerWhileGettingValueThruInstanceVariableAccessor(getAttributeName(), className, exception); |
| } |
| } |
| |
| /** |
| * instanceVariableName is converted to Field type. |
| */ |
| @Override |
| public void initializeAttributes(Class theJavaClass) throws DescriptorException { |
| if (getAttributeName() == null) { |
| throw DescriptorException.attributeNameNotSpecified(); |
| } |
| try { |
| setAttributeField(Helper.getField(theJavaClass, getAttributeName())); |
| } catch (NoSuchFieldException exception) { |
| throw DescriptorException.noSuchFieldWhileInitializingAttributesInInstanceVariableAccessor(getAttributeName(), theJavaClass.getName(), exception); |
| } catch (SecurityException exception) { |
| throw DescriptorException.securityWhileInitializingAttributesInInstanceVariableAccessor(getAttributeName(), theJavaClass.getName(), exception); |
| } |
| } |
| |
| /** |
| * Returns true if this attribute accessor has been initialized and now stores a reference to the |
| * class's attribute. An attribute accessor can become uninitialized on serialization. |
| */ |
| @Override |
| public boolean isInitialized(){ |
| return this.attributeField != null; |
| } |
| |
| @Override |
| public boolean isInstanceVariableAttributeAccessor() { |
| return true; |
| } |
| |
| /** |
| * Sets the value of the attributeField. |
| */ |
| protected void setAttributeField(Field field) { |
| attributeField = field; |
| } |
| |
| /** |
| * Sets the value of the instance variable in the object to the value. |
| */ |
| @Override |
| public void setAttributeValueInObject(Object anObject, Object value) throws DescriptorException { |
| try { |
| // PERF: Direct variable access. |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| AccessController.doPrivileged(new PrivilegedSetValueInField(this.attributeField, anObject, value)); |
| } catch (PrivilegedActionException exception) { |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), value, exception.getException()); |
| } |
| } else { |
| // PERF: Direct-var access. |
| this.attributeField.set(anObject, value); |
| } |
| } catch (IllegalArgumentException exception) { |
| // This is done to overcome VA Java bug because VA Java does not allow null to be set reflectively. |
| try { |
| // This is done to overcome VA Java bug because VA Java does not allow null to be set reflectively. |
| // Bug2910086 In JDK1.4, IllegalArgumentException is thrown if value is null. |
| // TODO: This code should be removed, it should not be required and may cause unwanted side-effects. |
| if (value == null) { |
| // cr 3737 If a null pointer was thrown because we attempted to set a null reference into a |
| // primitive create a primitive of value 0 to set in the object. |
| Class fieldClass = getAttributeClass(); |
| if (org.eclipse.persistence.internal.helper.Helper.isPrimitiveWrapper(fieldClass)) { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| AccessController.doPrivileged(new PrivilegedSetValueInField(this.attributeField, anObject, ConversionManager.getDefaultManager().convertObject(Integer.valueOf(0), fieldClass))); |
| } catch (PrivilegedActionException exc) { |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), null, exc.getException()); |
| } |
| } else { |
| org.eclipse.persistence.internal.security.PrivilegedAccessHelper.setValueInField(this.attributeField, anObject, ConversionManager.getDefaultManager().convertObject(Integer.valueOf(0), fieldClass)); |
| } |
| } |
| return; |
| } |
| } catch (IllegalAccessException accessException) { |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), null, exception); |
| } |
| |
| // TODO: This code should be removed, it should not be required and may cause unwanted side-effects. |
| // Allow XML change set to merge correctly since new value in XML change set is always String |
| try { |
| if (value instanceof String) { |
| Object newValue = ConversionManager.getDefaultManager().convertObject(value, getAttributeClass()); |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| AccessController.doPrivileged(new PrivilegedSetValueInField(this.attributeField, anObject, newValue)); |
| } catch (PrivilegedActionException exc) { |
| } |
| } else { |
| org.eclipse.persistence.internal.security.PrivilegedAccessHelper.setValueInField(this.attributeField, anObject, newValue); |
| } |
| return; |
| } |
| } catch (Exception e) { |
| // Do nothing and move on to throw the original exception |
| } |
| throw DescriptorException.illegalArgumentWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), getAttributeType().getName(), value, exception); |
| } catch (IllegalAccessException exception) { |
| if (value == null) { |
| return; |
| } |
| throw DescriptorException.illegalAccessWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), anObject.getClass().getName(), value, exception); |
| } catch (NullPointerException exception) { |
| try { |
| // TODO: This code should be removed, it should not be required and may cause unwanted side-effects. |
| //Bug2910086 In JDK1.3, NullPointerException is thrown if value is null. Add a null pointer check so that the TopLink exception is thrown if anObject is null. |
| if (anObject != null) { |
| // cr 3737 If a null pointer was thrown because we attempted to set a null reference into a |
| // primitive create a primitive of value 0 to set in the object. |
| Class fieldClass = getAttributeClass(); |
| if (org.eclipse.persistence.internal.helper.Helper.isPrimitiveWrapper(fieldClass) && (value == null)) { |
| if (org.eclipse.persistence.internal.helper.Helper.isPrimitiveWrapper(fieldClass)) { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| AccessController.doPrivileged(new PrivilegedSetValueInField(this.attributeField, anObject, ConversionManager.getDefaultManager().convertObject(Integer.valueOf(0), fieldClass))); |
| } catch (PrivilegedActionException exc) { |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), null, exc.getException()); |
| } |
| } else { |
| org.eclipse.persistence.internal.security.PrivilegedAccessHelper.setValueInField(this.attributeField, anObject, ConversionManager.getDefaultManager().convertObject(Integer.valueOf(0), fieldClass)); |
| } |
| } |
| } else { |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), value, exception); |
| } |
| } else { |
| // Some JVM's throw this exception for some very odd reason |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), value, exception); |
| } |
| } catch (IllegalAccessException accessException) { |
| throw DescriptorException.nullPointerWhileSettingValueThruInstanceVariableAccessor(getAttributeName(), value, exception); |
| } |
| } |
| } |
| } |