blob: f2873987eca214c491b3fd663454c443d43ccedd [file] [log] [blame]
/*
* 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
package org.eclipse.persistence.mappings.transformers;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedGetMethodParameterTypes;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping;
import org.eclipse.persistence.sessions.DataRecord;
import org.eclipse.persistence.sessions.Session;
/**
* @version $Header: MethodBasedAttributeTransformer.java 18-sep-2006.14:33:54 gyorke Exp $
* @author mmacivor
* @since release specific (what release of product did this appear in)
* This class is used to preserve the old method of doing Attribute Transformations
* on a transformation mapping. It is used internally when the older API is used on
* a TransformationMapping, and handles doing invocations on the user's domain class
*/
public class MethodBasedAttributeTransformer implements AttributeTransformer {
protected transient Method attributeTransformationMethod;
protected AbstractTransformationMapping mapping;
protected String methodName;
public MethodBasedAttributeTransformer() {
}
public MethodBasedAttributeTransformer(String methodName) {
this.methodName = methodName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String name) {
methodName = name;
}
public Method getAttributeTransformationMethod() {
return attributeTransformationMethod;
}
public void setAttributeTransformationMethod(Method theMethod) {
attributeTransformationMethod = theMethod;
}
/**
* INTERNAL:
* Initilizes the transformer. Looks up the transformation method on the
* domain class using reflection. This method can have either 1 or 2 parameters.
*/
@Override
public void initialize(AbstractTransformationMapping mapping) {
this.mapping = mapping;
final Class javaClass = this.mapping.getDescriptor().getJavaClass();
try {
// look for the one-argument version with Record first
Class[] parameterTypes = new Class[1];
parameterTypes[0] = ClassConstants.Record_Class;
attributeTransformationMethod = Helper.getDeclaredMethod(javaClass, methodName, parameterTypes);
} catch (NoSuchMethodException ex) {
try {
// if the one-argument version is not there, look for the two-argument version
Class[] parameterTypes = new Class[2];
parameterTypes[0] = ClassConstants.Record_Class;
parameterTypes[1] = ClassConstants.PublicInterfaceSession_Class;
attributeTransformationMethod = Helper.getDeclaredMethod(javaClass, methodName, parameterTypes);
} catch (NoSuchMethodException ex2) {
try {
//now look for the 2 argument version using Record and sessions Session
Class[] parameterTypes = new Class[2];
parameterTypes[0] = ClassConstants.Record_Class;
parameterTypes[1] = ClassConstants.SessionsSession_Class;
attributeTransformationMethod = Helper.getDeclaredMethod(javaClass, methodName, parameterTypes);
} catch (NoSuchMethodException ex3) {
throw DescriptorException.noSuchMethodOnInitializingAttributeMethod(this.mapping.getAttributeMethodName(), mapping, ex3);
} catch (SecurityException se) {
throw DescriptorException.securityOnInitializingAttributeMethod(this.mapping.getAttributeMethodName(), mapping, se);
}
} catch (SecurityException se) {
throw DescriptorException.securityOnInitializingAttributeMethod(this.mapping.getAttributeMethodName(), mapping, se);
}
} catch (SecurityException se) {
throw DescriptorException.securityOnInitializingAttributeMethod(this.mapping.getAttributeMethodName(), mapping, se);
}
if (attributeTransformationMethod.getReturnType() == ClassConstants.Void_Class) {
throw DescriptorException.returnTypeInGetAttributeAccessor(methodName, mapping);
}
}
/**
* INTERNAL:
* Build the attribute value by invoking the user's transformation method.
*/
@Override
public Object buildAttributeValue(DataRecord dataRecord, Object object, Session session) {
Class[] parameterTypes = null;
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try{
parameterTypes = AccessController.doPrivileged(new PrivilegedGetMethodParameterTypes(attributeTransformationMethod));
}catch (PrivilegedActionException ex){
throw (RuntimeException)ex.getCause();
}
}else{
parameterTypes = PrivilegedAccessHelper.getMethodParameterTypes(attributeTransformationMethod);
}
Object[] parameters = new Object[parameterTypes.length];
parameters[0] = dataRecord;
if (parameters.length == 2) {
parameters[1] = session;
}
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try{
return AccessController.doPrivileged(new PrivilegedMethodInvoker(attributeTransformationMethod, object, parameters));
}catch (PrivilegedActionException ex){
if (ex.getCause() instanceof IllegalArgumentException){
throw (IllegalArgumentException) ex.getCause();
}
if (ex.getCause() instanceof InvocationTargetException){
throw (InvocationTargetException) ex.getCause();
}
throw (RuntimeException) ex.getCause();
}
}else {
return PrivilegedAccessHelper.invokeMethod(attributeTransformationMethod, object, parameters);
}
} catch (IllegalAccessException exception) {
throw DescriptorException.illegalAccessWhileInvokingAttributeMethod(mapping, exception);
} catch (IllegalArgumentException exception) {
throw DescriptorException.illegalArgumentWhileInvokingAttributeMethod(mapping, exception);
} catch (InvocationTargetException exception) {
throw DescriptorException.targetInvocationWhileInvokingAttributeMethod(mapping, exception);
}
}
}