com.ebmwebsourcing.easycommons.lang.reflect.ReflectionHelper Maven / Gradle / Ivy
/****************************************************************************
* Copyright (c) 2010-2012, EBM WebSourcing - All rights reserved.
* Copyright (c) 2013, Linagora - All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University of California, Berkeley nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
package com.ebmwebsourcing.easycommons.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.ebmwebsourcing.easycommons.lang.UncheckedException;
/**
* @author Adrien Ruffie - EBM WebSourcing
*/
public final class ReflectionHelper {
private ReflectionHelper() {
}
/**
* Find all implemented interfaces recursively.
*
* @param clazz
* Class for which we want to know all implemented interfaces.
* @return An unmodifiable set of implemented interfaces.
*/
public static final Set> findAllImplementedInterfaces(Class> clazz) {
Set> implementedInterfaces = new HashSet>();
Class>[] directlyImplementedInterfaces = clazz.getInterfaces();
implementedInterfaces.addAll(Arrays.asList(directlyImplementedInterfaces));
for (Class> directlyImplementedInterface : directlyImplementedInterfaces) {
implementedInterfaces
.addAll(findAllImplementedInterfaces(directlyImplementedInterface));
}
if (clazz.getSuperclass() != null) {
implementedInterfaces.addAll(findAllImplementedInterfaces(clazz.getSuperclass()));
}
return implementedInterfaces;
}
/**
* Get a public method and wrap exceptions into unchecked exceptions.
*
* @param clazz
* @param methodName
* @param parameterTypes
* @return
*/
public static final Method getPublicMethod(Class> clazz, String methodName,
Class>... parameterTypes) {
assert clazz != null;
assert methodName != null;
try {
return clazz.getMethod(methodName, parameterTypes);
} catch (SecurityException e) {
throw new UncheckedException(String.format(
"Cannot get method '%s' on class '%s' (SecurityException).", methodName,
clazz.getSimpleName()), e);
} catch (NoSuchMethodException e) {
throw new UncheckedException(String.format(
"Cannot get method '%s' on class '%s' (NoSuchMethodException).", methodName,
clazz.getSimpleName()), e);
}
}
/**
* Get all public declared methods and wrap exceptions into unchecked
* exceptions.
*
* @param clazz
* @return
*/
public static final List getPublicDeclaredMethods(Class> clazz) {
assert clazz != null;
try {
List methods = new ArrayList();
for (Method m : clazz.getDeclaredMethods()) {
if (m.getModifiers() == (Modifier.PUBLIC)) {
methods.add(m);
}
}
return methods;
} catch (SecurityException e) {
throw new UncheckedException(
String.format("Cannot get methods on class '%s' (SecurityException).",
clazz.getSimpleName()), e);
}
}
/**
* Get a declared method and wrap exceptions into unchecked exceptions.
*
* @param clazz
* @param methodName
* @param parameterTypes
* @return
*/
public static final Method getDeclaredMethod(Class> clazz, String methodName,
Class>... parameterTypes) {
assert clazz != null;
assert methodName != null;
try {
return clazz.getDeclaredMethod(methodName, parameterTypes);
} catch (SecurityException e) {
throw new UncheckedException(String.format(
"Cannot get method '%s' on class '%s' (SecurityException).", methodName,
clazz.getSimpleName()), e);
} catch (NoSuchMethodException e) {
throw new UncheckedException(String.format(
"Cannot get method '%s' on class '%s' (NoSuchMethodException).", methodName,
clazz.getSimpleName()), e);
}
}
/**
* Invoke a method by reflection. This is a convenience method, wrapping all
* related exceptions into an unchecked exception.
*
* @param obj
* Object on which to invoke method.
* @param method
* Method to be invoked.
* @param args
* Method arguments.
* @return Result of invoked method.
*/
public static final Object invokeMethod(Object obj, Method method, Object... args)
throws InvocationTargetException {
assert obj != null;
try {
return method.invoke(obj, args);
} catch (IllegalArgumentException e) {
throw new UncheckedException(
String.format(
"Cannot invoke reflectively '%s' method on class '%s' (IllegalArgumentException).",
method.getName(), obj.getClass().getSimpleName()), e);
} catch (IllegalAccessException e) {
throw new UncheckedException(
String.format(
"Cannot invoke reflectively '%s' method on class '%s' (IllegalAccessException).",
method.getName(), obj.getClass().getSimpleName()), e);
}
}
/**
* Invoke a private method by reflection. This method can be used only in
* experimental projects This is a convenience method, wrapping all related
* exceptions into an unchecked exception.
*
* @param obj
* Object on which to invoke method.
* @param method
* Method to be invoked.
* @param args
* Method arguments.
* @return Result of invoked method.
* @deprecated Does not work correctly with private methods having parameter
* as {@link List}. Replaced by
* {@link #invokePrivateMethod(Object, String, Object[], Object[])}
*/
@Deprecated
public static final Object invokePrivateMethod(Object obj, String methodName, Object... args)
throws InvocationTargetException {
assert obj != null;
try {
List> parameterTypes = new ArrayList>();
for (Object param : args) {
parameterTypes.add(param.getClass());
}
Method method = getDeclaredMethod(obj.getClass(), methodName,
parameterTypes.toArray(new Class[parameterTypes.size()]));
method.setAccessible(true);
return method.invoke(obj, args);
} catch (IllegalArgumentException e) {
throw new UncheckedException(
String.format(
"Cannot invoke reflectively '%s' method on class '%s' (IllegalArgumentException).",
methodName, obj.getClass().getSimpleName()), e);
} catch (IllegalAccessException e) {
throw new UncheckedException(
String.format(
"Cannot invoke reflectively '%s' method on class '%s' (IllegalAccessException).",
methodName, obj.getClass().getSimpleName()), e);
}
}
/**
* Invoke a private method of an object instance, by reflection. This method
* can be used only in experimental projects. This is a convenience method,
* wrapping all related exceptions into an unchecked exception.
*
* @param obj
* Object on which to invoke method.
* @param method
* Method to be invoked.
* @param args
* Method arguments.
* @param types
* Method argument types.
* @return Result of invoked method.
*/
public static final Object invokePrivateMethod(final Object obj, final String methodName,
final Object[] args, final Class>[] types) throws InvocationTargetException {
assert obj != null;
return ReflectionHelper.invokePrivateMethod(null, obj, methodName, args, types);
}
/**
* Invoke a private method by reflection. This method can be used only in experimental projects This is a
* convenience method, wrapping all related exceptions into an unchecked exception.
*
* @param clazz
* The class of the object obj, can be null if the private method is not
* static.
* @param obj
* Object on which to invoke method. Is null if the private method to invoke is static.
* @param method
* Method to be invoked.
* @param args
* Method arguments.
* @param types
* Method argument types.
* @return Result of invoked method.
*/
public static final Object invokePrivateMethod(final Class> clazz, final Object obj,
final String methodName, final Object[] args, final Class>[] types)
throws InvocationTargetException {
final Class> actualClass;
if (clazz != null) {
actualClass = clazz;
} else if (obj != null) {
actualClass = obj.getClass();
} else {
throw new UncheckedException("A class or an object is required");
}
try {
final Method method = ReflectionHelper.getDeclaredMethod(actualClass, methodName, types);
method.setAccessible(true);
if (obj != null) {
return method.invoke(obj, args);
} else {
return method.invoke(null, args);
}
} catch (IllegalArgumentException e) {
throw new UncheckedException(
String.format(
"Cannot invoke reflectively '%s' method on class '%s' (IllegalArgumentException).", methodName,
actualClass.getSimpleName()), e);
} catch (IllegalAccessException e) {
throw new UncheckedException(
String.format(
"Cannot invoke reflectively '%s' method on class '%s' (IllegalAccessException).", methodName,
actualClass.getClass().getSimpleName()), e);
}
}
public static final T newInstance(Class clazz, Object... args)
throws InvocationTargetException {
try {
Constructor constructor = clazz.getConstructor();
return constructor.newInstance(args);
} catch (SecurityException e) {
throw new UncheckedException(String.format(
"Cannot get default constructor of class '%s' (SecurityException).",
clazz.getSimpleName()), e);
} catch (NoSuchMethodException e) {
throw new UncheckedException(String.format(
"Cannot get default constructor of class '%s' (NoSuchMethodException).",
clazz.getSimpleName()), e);
} catch (IllegalArgumentException e) {
throw new UncheckedException(String.format(
"Cannot create new instance of class '%s' (IllegalArgumentException).",
clazz.getSimpleName()), e);
} catch (InstantiationException e) {
throw new UncheckedException(String.format(
"Cannot create new instance of class '%s' (InstantiationException).",
clazz.getSimpleName()), e);
} catch (IllegalAccessException e) {
throw new UncheckedException(String.format(
"Cannot create new instance of class '%s' (IllegalAccessException).",
clazz.getSimpleName()), e);
}
}
public static final T newInstance(String className, ClassLoader cl, Object... args)
throws InvocationTargetException {
Class clazz = ReflectionHelper.loadClass(className, cl);
return ReflectionHelper.newInstance(clazz, args);
}
public static final Class loadClass(String className, ClassLoader cl) {
assert className != null;
try {
if (cl == null) {
cl = ReflectionHelper.class.getClassLoader();
if (cl == null) {
throw new UncheckedException("Cannot load classloader");
} else {
return (Class) cl.loadClass(className);
}
} else {
return (Class) cl.loadClass(className);
}
} catch (ClassNotFoundException e) {
throw new UncheckedException(String.format("Cannot load class '%s'", className), e);
}
}
public static final Collection findMethodsThatReturnType(Class> clazz,
Class> returnType) {
List methods = new ArrayList();
for (Method m : clazz.getMethods()) {
if (m.getReturnType().equals(returnType)) {
methods.add(m);
}
}
return methods;
}
/**
*
* Retrieve the value of a public, protected or private attribute by reflection. The attribute can be static and/or
* final.
*
*
* Notes:
*
* - If a attribute is a final attribute and its value must be changed later, set
removeFinalModifier
* to true to avoid the error ({@link IllegalAccessException} when setting an other value,
* -
* This method can be used only in experimental projects. This is a convenience method, wrapping all related
* exceptions into an unchecked exception.
*
*
*
* @param clazz
* The class of the object obj, can be null if the private method is not
* static.
* @param instance
* Object instance for which the attribute value must be set. Is null if the attribute is a
* static attribute.
* @param fieldName
* Name of the attribute to set
* @param removeFinalModifier
* Flag to remove the existing modifier 'final'.
* @return The value of the attribute
* @throws IllegalArgumentException
* If the attribute does not exist
*/
public static final Object getFieldValue(final Class> clazz, final Object instance, final String fieldName,
final boolean removeFinalModifier) throws IllegalArgumentException {
try {
final Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
if (removeFinalModifier) {
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
return field.get(instance);
} catch (final NoSuchFieldException e) {
throw new IllegalArgumentException(e);
} catch (final SecurityException e) {
throw new UncheckedException(
String.format(
"Cannot get reflectively value of field '%s' on class '%s' (SecurityException).",
fieldName, clazz.getSimpleName()), e);
} catch (final IllegalArgumentException e) {
throw new UncheckedException(
String.format(
"Cannot get reflectively value of field '%s' on class '%s' (IllegalArgumentException).",
fieldName, clazz.getSimpleName()), e);
} catch (final IllegalAccessException e) {
throw new UncheckedException(
String.format(
"Cannot get reflectively value of field '%s' on class '%s' (IllegalAccessException).",
fieldName, clazz.getSimpleName()), e);
}
}
/**
* @deprecated Prefer to use {@link #getFieldValue(Class, Object, String, boolean)} that manage final attributes and
* unexisting attributes
*/
@Deprecated
public static final Object getPrivateFieldValue(final Class> clazz, final Object instance, final String fieldName) {
try {
return getFieldValue(clazz, instance, fieldName, false);
} catch (final IllegalArgumentException e) {
return null;
}
}
public static final Object getFieldValue(Object obj, Field field) {
assert obj != null;
assert field != null;
try {
return field.get(obj);
} catch (IllegalArgumentException e) {
throw new UncheckedException(
String.format(
"Cannot get reflectively value of field '%s' on class '%s' (IllegalArgumentException).",
field.getName(), obj.getClass().getSimpleName()), e);
} catch (IllegalAccessException e) {
throw new UncheckedException(
String.format(
"Cannot get reflectively value of field '%s' on class '%s' (IllegalAccessException).",
field.getName(), obj.getClass().getSimpleName()), e);
}
}
/**
* @deprecated Prefer to use {@link #setFieldValue(Class, Object, String, Object, boolean)} that manages static and
* final field
*/
@Deprecated
public static void setPrivateField(final Object obj, final String fieldName, final Object value)
throws IllegalArgumentException {
setFieldValue(obj.getClass(), obj, fieldName, value, false);
}
/**
* Same as {@link #setFieldValue(Class, Object, String, Object, boolean)} but only for objects' fields
*
*/
public static void setFieldValue(final Object obj, final String fieldName, final Object value,
final boolean removeFinalModifier) throws IllegalArgumentException {
setFieldValue(obj.getClass(), obj, fieldName, value, removeFinalModifier);
}
/**
* Same as {@link #setFieldValue(Class, Object, String, Object, boolean)} but only for static fields
*
*/
public static void setFieldValue(final Class> clazz, final String fieldName, final Object value,
final boolean removeFinalModifier) throws IllegalArgumentException {
setFieldValue(clazz, null, fieldName, value, removeFinalModifier);
}
/**
*
* Set the value of a public, protected or private attribute by reflection. The attribute can be static and/or
* final.
*
*
* Notes:
*
* - If the attribute is a final attribute, the modifier 'final' is removed when setting the value.
* - An error ({@link IllegalAccessException} can occur on {@link Field#set(Object, Object)} if a final attribute
* to set was previously accessed without removing its modifier 'final',
* -
* This method can be used only in experimental projects. This is a convenience method, wrapping all related
* exceptions into an unchecked exception.
*
*
*
* @param clazz
* The class of the object obj, can be null if the private method is not
* static.
* @param obj
* Object instance for which the attribute value must be set. Is null if the attribute is a
* static attribute.
* @param fieldName
* Name of the attribute to set
* @param value
* The value to set to the attribute.
* @param removeFinalModifier
* Flag to remove the existing modifier 'final'.
* @return Result of invoked method.
*/
public static void setFieldValue(final Class> clazz, final Object obj, final String fieldName,
final Object value, final boolean removeFinalModifier) throws IllegalArgumentException {
assert clazz != null;
assert fieldName != null;
assert value != null;
/* Go and find the private field... */
boolean set = false;
final Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length && !set; ++i) {
if (fieldName.equals(fields[i].getName())) {
set = true;
try {
fields[i].setAccessible(true);
if (removeFinalModifier) {
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fields[i], fields[i].getModifiers() & ~Modifier.FINAL);
}
fields[i].set(obj, value);
} catch (final IllegalAccessException ex) {
throw new UncheckedException(
String.format(
"Cannot set reflectively value of field '%s' on class '%s' (IllegalAccessException).",
fieldName, clazz.getSimpleName()), ex);
} catch (final NoSuchFieldException ex) {
throw new UncheckedException(String.format(
"Cannot set reflectively value of field '%s' on class '%s' (NoSuchFieldException).",
fieldName, clazz.getSimpleName()), ex);
} catch (final SecurityException ex) {
throw new UncheckedException(String.format(
"Cannot set reflectively value of field '%s' on class '%s' (SecurityException).",
fieldName, clazz.getSimpleName()), ex);
}
}
}
if (!set) {
throw new IllegalArgumentException("Field doesn't exist: " + fieldName);
}
}
public static final void setFieldValue(Object obj, Field field, Object newValue) {
assert obj != null;
assert field != null;
try {
field.set(obj, newValue);
} catch (IllegalArgumentException e) {
throw new UncheckedException(
String.format(
"Cannot set reflectively value of field '%s' on class '%s' (IllegalArgumentException).",
field.getName(), obj.getClass().getSimpleName()), e);
} catch (IllegalAccessException e) {
throw new UncheckedException(
String.format(
"Cannot set reflectively value of field '%s' on class '%s' (IllegalAccessException).",
field.getName(), obj.getClass().getSimpleName()), e);
}
}
/**
* Test if the specified class is or inherited from the class with the
* specified canonical name
*
* @param clazz
* the class to check
* @param superClassName
* the class name to look for
* @return true if the
*/
public static final boolean isOrInheritedFrom(Class> clazz, String canonicalName) {
assert clazz != null;
assert canonicalName != null;
String clazzCanonicalName = clazz.getCanonicalName();
boolean isOrInheritedFrom;
if (canonicalName.equals(clazzCanonicalName)) {
isOrInheritedFrom = true;
} else {
Class> superclass = clazz.getSuperclass();
if (superclass != null) {
isOrInheritedFrom = isOrInheritedFrom(superclass, canonicalName);
} else {
isOrInheritedFrom = false;
}
}
return isOrInheritedFrom;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy