001/** 002 * Copyright 2011-2015 John Ericksen 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.parceler; 017 018import java.lang.reflect.*; 019import java.security.AccessController; 020import java.security.PrivilegedActionException; 021import java.security.PrivilegedExceptionAction; 022 023/** 024 * Utility class for performing a variety of operations through reflection. This functionality should be used sparingly 025 * as frequent calls can cause performance issues. 026 * 027 * @author John Ericksen 028 */ 029public final class InjectionUtil { 030 031 public static final String GET_FIELD_METHOD = "getField"; 032 public static final String SET_FIELD_METHOD = "setField"; 033 public static final String CALL_METHOD_METHOD = "callMethod"; 034 public static final String CALL_CONSTRUCTOR_METHOD = "callConstructor"; 035 036 private InjectionUtil() { 037 //singleton constructor 038 } 039 040 public static final class GenericType<T>{} 041 042 /** 043 * Returns the value of a field. 044 * 045 * @param returnType type of the field 046 * @param targetClass class represented by the target parameter 047 * @param target object containing the field 048 * @param field name of the field 049 * @param <T> type parameter 050 * @return field value 051 */ 052 public static <T> T getField(Class<T> returnType, Class<?> targetClass, Object target, String field) { 053 try { 054 Field declaredField = targetClass.getDeclaredField(field); 055 056 return AccessController.doPrivileged( 057 new GetFieldPrivilegedAction<T>(declaredField, target)); 058 059 } catch (NoSuchFieldException e) { 060 throw new ParcelerRuntimeException( 061 "NoSuchFieldException Exception during field injection: " + field + " in " + target.getClass(), e); 062 } catch (PrivilegedActionException e) { 063 throw new ParcelerRuntimeException("PrivilegedActionException Exception during field injection", e); 064 } catch (Exception e) { 065 throw new ParcelerRuntimeException("Exception during field injection", e); 066 } 067 } 068 069 public static <T> T getField(GenericType<T> returnType, Class<?> targetClass, Object target, String field) { 070 return (T) getField(Object.class, targetClass, target, field); 071 } 072 073 private static final class GetFieldPrivilegedAction<T> extends AccessibleElementPrivilegedAction<T, Field> { 074 075 private final Object target; 076 077 private GetFieldPrivilegedAction(Field classField, Object target) { 078 super(classField); 079 this.target = target; 080 } 081 082 @Override 083 public T run(Field classField) throws IllegalAccessException { 084 return (T) classField.get(target); 085 } 086 } 087 088 /** 089 * Updates field with the given value. 090 * 091 * @param targetClass class representing the object containing the field. 092 * @param target object containing the field to update 093 * @param field name of the field 094 * @param value object to update the field to 095 */ 096 public static void setField(Class<?> targetClass, Object target, String field, Object value) { 097 try { 098 Field classField = targetClass.getDeclaredField(field); 099 100 AccessController.doPrivileged( 101 new SetFieldPrivilegedAction(classField, target, value)); 102 103 } catch (NoSuchFieldException e) { 104 throw new ParcelerRuntimeException( 105 "NoSuchFieldException Exception during field injection: " + field + " in " + target.getClass(), e); 106 } catch (PrivilegedActionException e) { 107 throw new ParcelerRuntimeException("PrivilegedActionException Exception during field injection", e); 108 } catch (Exception e) { 109 throw new ParcelerRuntimeException("Exception during field injection", e); 110 } 111 } 112 113 private static final class SetFieldPrivilegedAction extends AccessibleElementPrivilegedAction<Void, Field> { 114 115 private final Object target; 116 private final Object value; 117 118 private SetFieldPrivilegedAction(Field classField, Object target, Object value) { 119 super(classField); 120 this.target = target; 121 this.value = value; 122 } 123 124 @Override 125 public Void run(Field classField) throws IllegalAccessException { 126 classField.set(target, value); 127 128 return null; 129 } 130 } 131 132 /** 133 * Calls a method with the provided arguments as parameters. 134 * 135 * @param retClass the method return value 136 * @param targetClass the instance class 137 * @param target the instance containing the method 138 * @param method the method name 139 * @param argClasses types of the method arguments 140 * @param args method arguments used during invocation 141 * @param <T> relating type parameter 142 * @return method return value 143 */ 144 public static <T> T callMethod(Class<T> retClass, Class<?> targetClass, Object target, String method, Class[] argClasses, Object[] args) { 145 try { 146 Method classMethod = targetClass.getDeclaredMethod(method, argClasses); 147 148 return AccessController.doPrivileged( 149 new SetMethodPrivilegedAction<T>(classMethod, target, args)); 150 151 } catch (NoSuchMethodException e) { 152 throw new ParcelerRuntimeException("Exception during method injection: NoSuchFieldException", e); 153 } catch (PrivilegedActionException e) { 154 throw new ParcelerRuntimeException("PrivilegedActionException Exception during field injection", e); 155 } catch (Exception e) { 156 throw new ParcelerRuntimeException("Exception during field injection", e); 157 } 158 } 159 160 public static <T> T callMethod(GenericType<T> retClass, Class<?> targetClass, Object target, String method, Class[] argClasses, Object[] args) { 161 return (T) callMethod(Object.class, targetClass, target, method, argClasses, args); 162 } 163 164 private static final class SetMethodPrivilegedAction<T> extends AccessibleElementPrivilegedAction<T, Method> { 165 166 private final Object target; 167 private final Object[] args; 168 169 private SetMethodPrivilegedAction(Method classMethod, Object target, Object[] args) { 170 super(classMethod); 171 this.target = target; 172 this.args = args; 173 } 174 175 public T run(Method classMethod) throws InvocationTargetException, IllegalAccessException { 176 return (T) classMethod.invoke(target, args); 177 } 178 } 179 180 181 /** 182 * Instantiates a class by calling the constructor. 183 * 184 * @param targetClass instance type to construct 185 * @param argClasses argument types accepted by the constructor 186 * @param args constructor argument values 187 * @param <T> relating type parameter 188 * @return instance created by constructor 189 */ 190 public static <T> T callConstructor(Class<T> targetClass, Class[] argClasses, Object[] args) { 191 T output; 192 193 try { 194 Constructor classConstructor = targetClass.getDeclaredConstructor(argClasses); 195 196 output = AccessController.doPrivileged( 197 new SetConstructorPrivilegedAction<T>(classConstructor, args)); 198 199 } catch (NoSuchMethodException e) { 200 throw new ParcelerRuntimeException("Exception during method injection: NoSuchMethodException", e); 201 } catch (PrivilegedActionException e) { 202 throw new ParcelerRuntimeException("PrivilegedActionException Exception during field injection", e); 203 } catch (Exception e) { 204 throw new ParcelerRuntimeException("Exception during field injection", e); 205 } 206 return output; 207 } 208 209 public static <T> T callConstructor(GenericType<T> targetClass, Class[] argClasses, Object[] args) { 210 return (T) callConstructor(Object.class, argClasses, args); 211 } 212 213 private static final class SetConstructorPrivilegedAction<T> extends AccessibleElementPrivilegedAction<T, Constructor> { 214 private final Object[] args; 215 216 private SetConstructorPrivilegedAction(Constructor classConstructor, Object[] args) { 217 super(classConstructor); 218 this.args = args; 219 } 220 221 @Override 222 public T run(Constructor classConstructor) throws InvocationTargetException, InstantiationException, IllegalAccessException { 223 return (T) classConstructor.newInstance(args); 224 } 225 } 226 227 private static abstract class AccessibleElementPrivilegedAction<T, E extends AccessibleObject> implements PrivilegedExceptionAction<T> { 228 229 private final E accessible; 230 231 protected AccessibleElementPrivilegedAction(E accessible) { 232 this.accessible = accessible; 233 } 234 235 @Override 236 public T run() throws Exception { 237 boolean previous = this.accessible.isAccessible(); 238 accessible.setAccessible(true); 239 240 T output = run(accessible); 241 242 accessible.setAccessible(previous); 243 244 return output; 245 } 246 247 /** 248 * Execute a Privileged Action against the given element which has been toggled to be accessible. 249 * 250 * @param element input AccessibleObject 251 * @return T 252 * @throws Exception 253 */ 254 public abstract T run(E element) throws Exception; 255 } 256}