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

org.unitils.util.ReflectionUtils Maven / Gradle / Ivy

Go to download

Unitils provides utilities to further simplify unit-testing with JUnit, DBUnit, EasyMock Hibernate and Spring. The goal is to make unit-testing easy and maintainable by offering utilities such as automatic DB-schema maintainance and equality assertion through reflection.

There is a newer version: 3.4.6
Show newest version
/*
 * Copyright 2006-2007,  Unitils.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.unitils.util;

import org.apache.commons.lang.StringUtils;
import org.unitils.core.UnitilsException;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Utility methods that use reflection for instance creation or class inspection.
 *
 * @author Filip Neven
 * @author Tim Ducheyne
 */
public class ReflectionUtils {


    /**
     * Creates an instance of the class with the given name.
     * The class's no argument constructor is used to create an instance.
     *
     * @param className           The name of the class, not null
     * @param bypassAccessibility If true, no exception is thrown if the parameterless constructor is not public
     * @return An instance of this class
     * @throws UnitilsException if the class could not be found or no instance could be created
     */
    @SuppressWarnings({"unchecked"})
    public static  T createInstanceOfType(String className, boolean bypassAccessibility) {
        try {
            Class type = Class.forName(className);
            return (T) createInstanceOfType(type, bypassAccessibility);

        } catch (ClassCastException e) {
            throw new UnitilsException("Class " + className + " is not of expected type.", e);

        } catch (NoClassDefFoundError e) {
            throw new UnitilsException("Unable to load class " + className, e);

        } catch (ClassNotFoundException e) {
            throw new UnitilsException("Class " + className + " not found", e);

        } catch (Exception e) {
            throw new UnitilsException("Error while instantiating class " + className, e);
        }
    }


    /**
     * Creates an instance of the given type
     *
     * @param                  The type of the instance
     * @param type                The type of the instance
     * @param bypassAccessibility If true, no exception is thrown if the parameterless constructor is not public
     * @return An instance of this type
     * @throws UnitilsException If an instance could not be created
     */
    public static  T createInstanceOfType(Class type, boolean bypassAccessibility) {
        try {
            Constructor constructor = type.getDeclaredConstructor();
            if (bypassAccessibility) {
                constructor.setAccessible(true);
            }
            return constructor.newInstance();

        } catch (Exception e) {
            throw new UnitilsException("Error while trying to create object of class " + type.getName(), e);
        }
    }


    /**
     * Returns the value of the given field (may be private) in the given object
     *
     * @param object The object containing the field, null for static fields
     * @param field  The field, not null
     * @return The value of the given field in the given object
     * @throws UnitilsException if the field could not be accessed
     */
    public static Object getFieldValue(Object object, Field field) {
        try {
            field.setAccessible(true);
            return field.get(object);

        } catch (IllegalArgumentException e) {
            throw new UnitilsException("Error while trying to access field " + field, e);

        } catch (IllegalAccessException e) {
            throw new UnitilsException("Error while trying to access field " + field, e);
        }
    }


    /**
     * Sets the given value to the given field on the given object
     *
     * @param object The object containing the field, not null
     * @param field  The field, not null
     * @param value  The value for the given field in the given object
     * @throws UnitilsException if the field could not be accessed
     */
    public static void setFieldValue(Object object, Field field, Object value) {
        try {
            field.setAccessible(true);
            field.set(object, value);

        } catch (IllegalArgumentException e) {
            throw new UnitilsException("Unable to assign the value to field: " + field.getName() + ". Ensure that this field is of the correct type.", e);

        } catch (IllegalAccessException e) {
            // Cannot occur, since field.accessible has been set to true
            throw new UnitilsException("Error while trying to access field " + field, e);
        }
    }


    /**
     * Sets the given value to the given field and setters on the given object.
     *
     * @param object        The object containing the field and setters, not null
     * @param fields        The fields, not null
     * @param setterMethods The setter methods, not null
     * @param value         The value for the given field and setters in the given object
     */
    public static void setFieldAndSetterValue(Object object, List fields, List setterMethods, Object value) {
        for (Field field : fields) {
            try {
                setFieldValue(object, field, value);

            } catch (UnitilsException e) {
                throw new UnitilsException("Unable to assign the value to field: " + field.getName() + ". Ensure that this field is of the correct type.", e);
            }
        }
        for (Method method : setterMethods) {
            if (!isSetter(method)) {
                throw new UnitilsException("Method " + method.getName() + " is expected to be a setter method, but is not.");
            }
            try {
                invokeMethod(object, method, value);

            } catch (UnitilsException e) {
                throw new UnitilsException("Unable to invoke method: " + object.getClass().getSimpleName() + "." + method.getName() + ". Ensure that " +
                        "this method has following signature: void myMethod(ValueType value).", e);
            } catch (InvocationTargetException e) {
                throw new UnitilsException("Unable to invoke method: " + object.getClass().getSimpleName() + "." + method.getName() + ". Method " +
                        "has thrown an exception.", e.getCause());
            }
        }
    }


    /**
     * Invokes the given method with the given parameters on the given target object
     *
     * @param target    The object containing the method, not null
     * @param method    The method, not null
     * @param arguments The method arguments
     * @return The result of the invocation, null if void
     * @throws UnitilsException          if the method could not be invoked
     * @throws InvocationTargetException If the called method throwed an exception
     */
    @SuppressWarnings({"unchecked"})
    public static  T invokeMethod(Object target, Method method, Object... arguments) throws InvocationTargetException {
        try {
            method.setAccessible(true);
            return (T) method.invoke(target, arguments);

        } catch (ClassCastException e) {
            throw new UnitilsException("Unable to invoke method. Unexpected return type " + method, e);

        } catch (IllegalArgumentException e) {
            throw new UnitilsException("Error while invoking method " + method, e);

        } catch (IllegalAccessException e) {
            throw new UnitilsException("Error while invoking method " + method, e);
        }
    }


    /**
     * Returns all declared fields of the given class that are assignable from the given type.
     *
     * @param clazz    The class to get fields from, not null
     * @param type     The type, not null
     * @param isStatic True if static fields are to be returned, false for non-static
     * @return A list of Fields, empty list if none found
     */
    public static List getFieldsAssignableFrom(Class clazz, Class type, boolean isStatic) {
        List fieldsOfType = new ArrayList();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.getType().isAssignableFrom(type) && Modifier.isStatic(field.getModifiers()) == isStatic) {
                fieldsOfType.add(field);
            }
        }
        return fieldsOfType;
    }


    /**
     * Returns the fields in the given class that have the exact given type. The class's superclasses are also
     * investigated.
     *
     * @param clazz    The class to get the field from, not null
     * @param type     The type, not null
     * @param isStatic True if static fields are to be returned, false for non-static
     * @return The fields with the given type
     */
    public static List getFieldsOfType(Class clazz, Class type, boolean isStatic) {
        List fields = getFieldsOfTypeIgnoreSuper(clazz, type, isStatic);
        Class superClass = clazz.getSuperclass();
        if (!superClass.equals(Object.class)) {
            fields.addAll(getFieldsOfType(superClass, type, isStatic));
        }
        return fields;
    }


    /**
     * Returns the fields in the given class that have the exact given type. The class's superclasses are not
     * investigated.
     *
     * @param clazz    The class to get the field from, not null
     * @param type     The type, not null
     * @param isStatic True if static fields are to be returned, false for non-static
     * @return The fields with the given type
     */
    private static List getFieldsOfTypeIgnoreSuper(Class clazz, Class type, boolean isStatic) {
        List fields = new ArrayList();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.getType().equals(type) && isStatic == Modifier.isStatic(field.getModifiers())) {
                fields.add(field);
            }
        }
        return fields;
    }


    /**
     * Returns all declared setter methods of fields of the given class that are assignable from the given type.
     *
     * @param clazz    The class to get setters from, not null
     * @param type     The type, not null
     * @param isStatic True if static setters are to be returned, false for non-static
     * @return A list of Methods, empty list if none found
     */
    public static List getSettersAssignableFrom(Class clazz, Class type, boolean isStatic) {
        List settersAssignableFrom = new ArrayList();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (isSetter(method) && method.getParameterTypes()[0].isAssignableFrom(type)
                    && isStatic == Modifier.isStatic(method.getModifiers())) {
                settersAssignableFrom.add(method);
            }
        }
        return settersAssignableFrom;
    }


    /**
     * Returns the setter methods in the given class that have an argument with the exact given type. The class's
     * superclasses are also investigated.
     *
     * @param clazz    The class to get the setter from, not null
     * @param type     The type, not null
     * @param isStatic True if static setters are to be returned, false for non-static
     * @return All setters for an object of the given type
     */
    public static List getSettersOfType(Class clazz, Class type, boolean isStatic) {
        List setters = getSettersOfTypeIgnoreSuper(clazz, type, isStatic);
        Class superClass = clazz.getSuperclass();
        if (!superClass.equals(Object.class)) {
            setters.addAll(getSettersOfType(superClass, type, isStatic));
        }
        return setters;
    }

    /**
     * Returns the setter methods in the given class that have an argument with the exact given type. The class's
     * superclasses are not investigated.
     *
     * @param clazz    The class to get the setter from, not null
     * @param type     The type, not null
     * @param isStatic True if static setters are to be returned, false for non-static
     * @return All setters for an object of the given type
     */
    private static List getSettersOfTypeIgnoreSuper(Class clazz, Class type, boolean isStatic) {
        List settersOfType = new ArrayList();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (isSetter(method) && method.getParameterTypes()[0].equals(type)
                    && isStatic == Modifier.isStatic(method.getModifiers())) {
                settersOfType.add(method);
            }
        }
        return settersOfType;
    }


    /**
     * From the given class, returns the setter for the property with the given name and 1 argument. If isStatic == true,
     * a static setter is searched. If no such setter exists in the given class, null is returned
     *
     * @param clazz        The class to get the setter from, not null
     * @param propertyName The name of the property, not null
     * @param isStatic     True if a static setter is to be returned, false for non-static
     * @return The setter method that matches the given parameters, null if not found
     */
    public static Method getSetter(Class clazz, String propertyName, boolean isStatic) {
        String setterName = "set" + StringUtils.capitalize(propertyName);
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (isSetter(method) && setterName.equals(method.getName())
                    && isStatic == Modifier.isStatic(method.getModifiers())) {
                return method;
            }
        }
        return null;
    }


    /**
     * From the given class, returns the getter for the given propertyname. If isStatic == true,
     * a static getter is searched. If no such getter exists in the given class, null is returned.
     *
     * @param clazz        The class to get the setter from, not null
     * @param propertyName The name of the property, not null
     * @param isStatic     True if a static getter is to be returned, false for non-static
     * @return The getter method that matches the given parameters, or null if no such method exists
     */
    public static Method getGetter(Class clazz, String propertyName, boolean isStatic) {
        String getterName = "get" + StringUtils.capitalize(propertyName);
        try {
            Method getter = clazz.getDeclaredMethod(getterName);
            if (isStatic == Modifier.isStatic(getter.getModifiers())) {
                return getter;
            } else {
                return null;
            }
        } catch (NoSuchMethodException e) {
            return null;
        }
    }


    /**
     * From the given class, returns the getter for the given setter method. If no such getter exists in the
     * given class, null is returned.
     *
     * @param setter The setter method, not null
     * @return The getter method that matches the given setter, or null if no such method exists
     */
    public static Method getGetter(Method setter) {
        if (!isSetter(setter)) {
            return null;
        }
        String getterName = "get" + setter.getName().substring(3);
        try {
            Method getter = setter.getDeclaringClass().getDeclaredMethod(getterName);
            if (Modifier.isStatic(setter.getModifiers()) == Modifier.isStatic(getter.getModifiers())) {
                return getter;
            } else {
                return null;
            }
        } catch (NoSuchMethodException e) {
            return null;
        }
    }


    /**
     * From the given class, returns the field with the given name. isStatic indicates if it should be a static
     * field or not.
     *
     * @param clazz     The class to get the field from, not null
     * @param fieldName The name, not null
     * @param isStatic  True if a static field is to be returned, false for non-static
     * @return The field that matches the given parameters, or null if no such field exists
     */
    public static Field getFieldWithName(Class clazz, String fieldName, boolean isStatic) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            if (Modifier.isStatic(field.getModifiers()) == isStatic) {
                return field;
            } else {
                return null;
            }
        } catch (NoSuchFieldException e) {
            return null;
        }
    }


    /**
     * Gets the enum value that has the given name.
     *
     * @param enumClass     The enum class, not null
     * @param enumValueName The name of the enum value, not null
     * @return The actual enum value, not null
     * @throws UnitilsException if no value could be found with the given name
     */
    public static > T getEnumValue(Class enumClass, String enumValueName) {
        T[] enumValues = enumClass.getEnumConstants();
        for (T enumValue : enumValues) {
            if (enumValueName.equalsIgnoreCase(enumValue.name())) {

                return enumValue;
            }
        }
        throw new UnitilsException("Unable to find a enum value in enum: " + enumClass + ", with value name: " + enumValueName);
    }


    /**
     * For each method, check if it can be a setter for an object of the given type. A setter is a method with
     * the following properties:
     * 
    *
  • Method name is > 3 characters long and starts with set
  • *
  • The fourth character is in uppercase
  • *
  • The method has one parameter, with the type of the property to set
  • *
* * @param method The method to check, not null * @return True if the given method is a setter, false otherwise */ public static boolean isSetter(Method method) { String methodName = method.getName(); if (methodName.length() > 3 && method.getName().startsWith("set") && method.getParameterTypes().length == 1) { String fourthLetter = methodName.substring(3, 4); if (fourthLetter.toUpperCase().equals(fourthLetter)) { return true; } } return false; } /** * Gets the name of the field for the given setter method. An exception is raised when * the field name could not be extracted. * * @param setterMethod The method, not null * @return The field name, not null */ public static String getFieldName(Method setterMethod) { String methodName = setterMethod.getName(); if (methodName.length() < 4 || !methodName.startsWith("set")) { throw new UnitilsException("Unable to get field name for setter method " + setterMethod); } return methodName.substring(3, 4).toLowerCase() + methodName.substring(4); } /** * Gets the class for the given name. * An UnitilsException is thrown when the class could not be loaded. * * @param className The name of the class, not null * @return The class, not null */ public static Class getClassWithName(String className) { try { return Class.forName(className); } catch (Throwable t) { throw new UnitilsException("Could not load class with name " + className, t); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy