All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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