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

patterntesting.runtime.util.ReflectionHelper Maven / Gradle / Ivy

Go to download

PatternTesting Runtime (patterntesting-rt) is the runtime component for the PatternTesting framework. It provides the annotations and base classes for the PatternTesting testing framework (e.g. patterntesting-check, patterntesting-concurrent or patterntesting-exception) but can be also used standalone for classpath monitoring or profiling. It uses AOP and AspectJ to perform this feat.

There is a newer version: 2.5.0
Show newest version
/*
 * $Id: ReflectionHelper.java,v 1.21 2016/03/22 22:28:00 oboehm Exp $
 *
 * Copyright (c) 2009 by Oliver Boehm
 *
 * 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 orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 09.03.2009 by oliver ([email protected])
 */
package patterntesting.runtime.util;

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

import org.apache.commons.lang3.StringUtils;
import org.slf4j.*;

import patterntesting.annotation.check.runtime.MayReturnNull;

/**
 * This class is a helper class to access some fields via reflection. Normally
 * you should avoid reflection. Handle with care if you use it.
 *
 * @author oliver
 * @version $Revision: 1.21 $
 * @since 09.03.2009
 */
public class ReflectionHelper {

     private static final Logger LOG = LoggerFactory.getLogger(ReflectionHelper.class);

     /** Utility class - no need to instantiate it */
     private ReflectionHelper() {}

    /**
     * Tries to get the wanted field.
     *
     * @param cl the cl
     * @param name the name
     *
     * @return the wanted field
     *
     * @throws NoSuchFieldException the no such field exception
     */
    public static Field getField(final Class cl, final String name)
            throws NoSuchFieldException {
        try {
            Field field = cl.getDeclaredField(name);
            field.setAccessible(true);
            return field;
        } catch (NoSuchFieldException e) {
            Class superclass = cl.getSuperclass();
            if (superclass == null) {
                throw e;
            } else {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("using " + superclass + " to get " + cl.getName()
                            + "." + name + "...");
                }
                return ReflectionHelper.getField(superclass, name);
            }
        }
    }

    /**
     * Returns true if the given object have a field with the given name.
     *
     * @param obj the obj
     * @param name the name
     * @return true, if successful
     * @since 1.5
     */
    public static boolean hasField(final Object obj, final String name) {
        return hasField(obj.getClass(), name);
    }

    /**
     * Returns true if the given class have a field with the given name.
     *
     * @param clazz the clazz
     * @param name the name
     * @return true, if successful
     * @since 1.5
     */
    public static boolean hasField(final Class clazz, final String name) {
        if (StringUtils.isEmpty(name)) {
            return false;
        }
        try {
            getField(clazz, name);
            return true;
        } catch (NoSuchFieldException ex) {
            LOG.debug("Will return false because {} has no field '{}' ({}).", clazz, name, ex);
            return false;
        }
    }

    /**
     * If it can it returns the value of the given field. If not it throws an
     * exception.
     *
     * @param target the target object
     * @param name the name
     * @return the field value
     * @throws NoSuchFieldException the no such field exception
     * @throws IllegalAccessException the illegal access exception
     */
    public static Object getFieldValue(final Object target, final String name)
            throws NoSuchFieldException, IllegalAccessException {
        Field field = ReflectionHelper.getField(target.getClass(), name);
        return field.get(target);
    }

    /**
     * Sets the field value of the given target. With this method you can set
     * private attributes, e.g. for testing.
     *
     * @param target the target
     * @param name the name
     * @param value the value
     * @throws NoSuchFieldException the no such field exception
     * @throws IllegalArgumentException the illegal argument exception
     * @throws IllegalAccessException the illegal access exception
     * @since 1.6
     */
    public static void setFieldValue(final Object target, final String name, final String value) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Field field = ReflectionHelper.getField(target.getClass(), name);
        field.set(target, value);
    }

    /**
     * To get all uninitialized field you can call this method.
     *
     * @param obj the object where to get the fields from
     *
     * @return a collecion of unitialized fields (can be empty)
     */
    public static Collection getUninitializedNonStaticFields(final Object obj) {
        Collection unitializedFields = new ArrayList();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            try {
                fields[i].setAccessible(true);
                if ((fields[i].get(obj) == null) && !isStatic(fields[i])) {
                    unitializedFields.add(fields[i]);
                }
            } catch (IllegalArgumentException e) {
                LOG.info(e + " => " + fields[i] + " ignored");
            } catch (IllegalAccessException e) {
                LOG.debug("Cannot access " + fields[i] + " => ignored: ", e);
            }
        }
        return unitializedFields;
    }

    /**
     * Checks if the given field is static.
     *
     * @param field the field
     * @return true, if is static
     */
    public static boolean isStatic(final Field field) {
        int m = field.getModifiers();
        return Modifier.isStatic(m);
    }

    /**
     * To short string.
     *
     * @param field the field
     *
     * @return the string
     */
    public static String toShortString(final Field field) {
        return field.getType().getSimpleName() + " " + field.getName();
    }

    /**
     * To short string.
     *
     * @param fields the fields
     *
     * @return the string
     */
    public static String toShortString(final Collection fields) {
        StringBuilder sbuf = new StringBuilder();
        for (Iterator iterator = fields.iterator(); iterator.hasNext();) {
            Field field = iterator.next();
            sbuf.append(", ");
            sbuf.append(toShortString(field));
        }
        return sbuf.substring(2);
    }

    /**
     * Gets the method.
     *
     * @param cl the cl
     * @param name the name
     * @param args the args
     * @return the method
     * @throws NoSuchMethodException the no such method exception
     */
    public static Method getMethod(final Class cl, final String name, final Object... args)
            throws NoSuchMethodException {
        Class parameterTypes[] = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            parameterTypes[i] = args[i].getClass();
        }
        return getMethod(cl, name, parameterTypes);
    }

    /**
     * Gets the method.
     *
     * @param cl e.g. class java.lang.ClassLoader
     * @param name e.g. "getPackages"
     * @param parameterTypes the parameter types
     * @return a Method object
     * @throws NoSuchMethodException the no such method exception
     */
    public static Method getMethod(final Class cl, final String name,
            final Class... parameterTypes) throws NoSuchMethodException {
	    try {
	        return cl.getDeclaredMethod(name, parameterTypes);
	    } catch (NoSuchMethodException origException) {
	        try {
    	        try {
    	            return findMethod(cl, name, parameterTypes);
    	        } catch (NoSuchMethodException nsme) {
        	        Class superclass = cl.getSuperclass();
        	        if (superclass == null) {
                        LOG.debug("No method '{}' and no superclass for {} found:", name, cl, nsme);
        	            throw origException;
        	        } else {
        	            return getMethod(superclass, name, parameterTypes);
        	        }
    	        }
            } catch (NoSuchMethodException derived) {
                LOG.debug("Method '{}' also not found in superclass:", name, derived);
                throw origException;
            }
	    }
	}

    private static Method findMethod(final Class cl, final String name,
            final Class... parameterTypes) throws NoSuchMethodException {
        Method[] methods = cl.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            if (name.equals(methods[i].getName()) && matchesParameters(methods[i], parameterTypes)) {
                return methods[i];
            }
        }
        throw new NoSuchMethodException(cl.getName() + "." + name + "("
                + Converter.toShortString(parameterTypes) + ")");
    }

    private static boolean matchesParameters(final Method method, final Class[] matchingTypes) {
        Class[] parameterTypes = method.getParameterTypes();
        if (parameterTypes.length != matchingTypes.length) {
            return false;
        }
        for (int i = 0; i < parameterTypes.length; i++) {
            if (!matches(parameterTypes[i], matchingTypes[i])) {
                return false;
            }
        }
        return true;
    }

    private static boolean matches(final Class parameterType, final Class matchingType) {
        if (parameterType.isAssignableFrom(matchingType)) {
            return true;
        }
        if (parameterType.isPrimitive()) {
            if (parameterType.equals(boolean.class)) {
                return matchingType.equals(Boolean.class);
            } else if (parameterType.equals(byte.class)) {
                return matchingType.equals(Byte.class);
            } else if (parameterType.equals(char.class)) {
                return matchingType.equals(Character.class);
            } else if (parameterType.equals(short.class)) {
                return matchingType.equals(Short.class);
            } else if (parameterType.equals(int.class)) {
                return matchingType.equals(Integer.class);
            } else if (parameterType.equals(long.class)) {
                return matchingType.equals(Long.class);
            } else if (parameterType.equals(float.class)) {
                return matchingType.equals(Float.class);
            } else if (parameterType.equals(double.class)) {
                return matchingType.equals(Double.class);
            } else {
                LOG.warn("unknown primitive type \"" + parameterType + "\" not yet supported - sorry!");
                return false;
            }
        }
        return false;
    }

    /**
	 * Invoke method. This could be also a protected or private method.
	 *
	 * @param target the target
	 * @param name the method name
	 * @param args the args for the method
	 * @return the result of the method.
	 */
    public static Object invokeMethod(final Object target, final String name, final Object... args) {
	    try {
            Method method = getMethod(target.getClass(), name, args);
            method.setAccessible(true);
            return method.invoke(target, args);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(
                    "no method \"" + name + "(" + toParamString(args) + ")\" in " + target.getClass(), e);
        } catch (IllegalAccessException iae) {
            throw new RuntimeException("can't access method \"" + name + "\" in "
                    + target.getClass(), iae);
        } catch (InvocationTargetException ite) {
            throw new RuntimeException("exception in method \"" + name + "\" of "
                    + target.getClass(), ite.getTargetException());
        }
	}

    private static String toParamString(final Object[] args) {
        Class paramTypes[] = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            paramTypes[i] = args[i].getClass();
        }
        return Converter.toShortString(paramTypes);
    }

    /**
     * Checks if the given object has something which looks like an id.
     *
     * @param obj the obj
     * @return true, if successful
     * @since 1.6 (01.06.2015)
     */
    public static boolean hasId(final Object obj) {
        return hasId(obj.getClass());
    }

    /**
     * Checks if the given class has something which looks like an id attribute.
     *
     * @param clazz the clazz
     * @return true, if successful
     */
    public static boolean hasId(final Class clazz) {
        if (getIdField(clazz) != null) {
            return true;
        }
        return getIdGetter(clazz) != null;
    }

    /**
     * Gets the id of the given object.
     *
     * @param obj the obj
     * @return the id
     * @since 1.6 (01.06.2015)
     */
    public static Object getId(final Object obj) {
        Field idField = getIdField(obj.getClass());
        try {
            if (idField != null) {
                idField.setAccessible(true);
                return idField.get(obj);
            }
            Method getter = getIdGetter(obj.getClass());
            getter.setAccessible(true);
            return getter.invoke(obj);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("cannot access id of " + obj);
        } catch (InvocationTargetException e) {
            throw new IllegalArgumentException("cannot invoke get for id of " + obj);
        }
    }

    @MayReturnNull
    private static Field getIdField(final Class clazz) {
        Field[] fields = clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if ("id".equalsIgnoreCase(fields[i].getName())) {
                return fields[i];
            }
        }
        Class superclass = clazz.getSuperclass();
        return superclass == null ? null : getIdField(superclass);
    }

    @MayReturnNull
    private static Method getIdGetter(final Class clazz) {
        Method[] methods = clazz.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            if ("getid".equalsIgnoreCase(methods[i].getName())) {
                return methods[i];
            }
        }
        Class superclass = clazz.getSuperclass();
        return superclass == null ? null : getIdGetter(superclass);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy