com.evolveum.midpoint.util.ReflectionUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.util.ReflectionUtil.java

Source

/*
 * Copyright (c) 2010-2013 Evolveum
 *
 * 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 com.evolveum.midpoint.util;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import javax.xml.xpath.XPathFunctionException;

import org.apache.commons.lang.StringUtils;

/**
 * @author semancik
 *
 */
public class ReflectionUtil {

    /**
     * Try to get java property from the object by reflection
     */
    public static <T> T getJavaProperty(Object object, String propertyName, Class<T> propetyClass) {
        String getterName = getterName(propertyName);
        Method method;
        try {
            method = object.getClass().getMethod(getterName);
        } catch (SecurityException e) {
            throw new IllegalArgumentException(
                    "Security error getting getter for property " + propertyName + ": " + e.getMessage(), e);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(
                    "No getter for property " + propertyName + " in " + object + " (" + object.getClass() + ")");
        }
        if (method == null) {
            throw new IllegalArgumentException(
                    "No getter for property " + propertyName + " in " + object + " (" + object.getClass() + ")");
        }
        if (!propetyClass.isAssignableFrom(method.getReturnType())) {
            throw new IllegalArgumentException(
                    "The getter for property " + propertyName + " returns " + method.getReturnType() + ", expected "
                            + propetyClass + " in " + object + " (" + object.getClass() + ")");
        }
        try {
            return (T) method.invoke(object);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(
                    "Error invoking getter for property " + propertyName + " in " + object + " ("
                            + object.getClass() + "): " + e.getClass().getSimpleName() + ": " + e.getMessage(),
                    e);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException(
                    "Error invoking getter for property " + propertyName + " in " + object + " ("
                            + object.getClass() + "): " + e.getClass().getSimpleName() + ": " + e.getMessage(),
                    e);
        } catch (InvocationTargetException e) {
            throw new IllegalArgumentException(
                    "Error invoking getter for property " + propertyName + " in " + object + " ("
                            + object.getClass() + "): " + e.getClass().getSimpleName() + ": " + e.getMessage(),
                    e);
        }
    }

    public static boolean hasJavaProperty(Object object, String propertyName) {
        return findGetter(object, propertyName) != null;
    }

    public static Method findGetter(Object object, String propertyName) {
        String getterName = getterName(propertyName);
        return findMethod(object, getterName, 0);
    }

    private static String getterName(String propertyName) {
        return "get" + StringUtils.capitalize(propertyName);
    }

    public static Method findMethod(Object object, String methodName, int arity) {
        for (Method method : object.getClass().getMethods()) {
            if (method.getName().equals(methodName) && method.getParameterTypes().length == arity
                    && !method.isVarArgs()) {
                return method;
            }
        }
        return null;
    }

    public static Method findMethod(Object object, String methodName, List<?> argList) throws SecurityException {
        Method method = findMethodDirect(object, methodName, argList);
        if (method != null) {
            return method;
        }
        method = findMethodCompatible(object, methodName, argList);
        if (method != null) {
            return method;
        }
        // We cannot find method directly. Try varargs.
        method = findVarArgsMethod(object, methodName);
        return method;
    }

    private static Method findMethodDirect(Object object, String methodName, List<?> argList)
            throws SecurityException {
        Class<?>[] parameterTypes = new Class[argList.size()];
        for (int i = 0; i < argList.size(); i++) {
            parameterTypes[i] = argList.get(i).getClass();
        }
        try {
            return object.getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    /**
     * Rough lookup of a compatible method. It takes first method with matching name, number of parameters and compatible
     *  parameter values. It is not perfect, e.g. it cannot select foo(String) instead of foo(Object). But it is better than
     *  nothing. And stock Java reflection has really nothing.
     */
    private static Method findMethodCompatible(Object object, String methodName, List<?> argList)
            throws SecurityException {
        for (Method method : object.getClass().getMethods()) {
            if (method.getName().equals(methodName)) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == argList.size()) {
                    boolean wrong = false;
                    for (int i = 0; i < parameterTypes.length; i++) {
                        Object arg = argList.get(i);
                        if (arg == null) {
                            // null argument matches any parameter type
                        } else {
                            if (!parameterTypes[i].isAssignableFrom(arg.getClass())) {
                                wrong = true;
                                break;
                            }
                        }
                    }
                    if (!wrong) {
                        // We got it. We have compatible signature here.
                        return method;
                    }
                }
            }
        }
        return null;
    }

    public static Method findVarArgsMethod(Object object, String methodName) {
        for (Method method : object.getClass().getMethods()) {
            if (method.getName().equals(methodName) && method.isVarArgs()) {
                return method;
            }
        }
        return null;
    }

    public static Object invokeMethod(Object object, String methodName, List<?> argList)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Method method = findMethod(object, methodName, argList);
        if (method == null) {
            throw new NoSuchMethodException(
                    "No method " + methodName + " for arguments " + debugDumpArgList(argList) + " in " + object);
        }
        Object[] args = argList.toArray();
        if (method.isVarArgs()) {
            Class<?> parameterTypeClass = method.getParameterTypes()[0];
            Object[] varArgs = (Object[]) Array.newInstance(parameterTypeClass.getComponentType(), args.length);
            for (int i = 0; i < args.length; i++) {
                varArgs[i] = args[i];
            }
            args = new Object[] { varArgs };
        }
        try {
            return method.invoke(object, args);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(
                    e.getMessage() + " for arguments " + debugDumpArgList(argList) + " in " + object, e);
        }
    }

    public static String debugDumpArgList(List<?> argList) {
        StringBuilder sb = new StringBuilder();
        boolean sep = false;
        for (Object arg : argList) {
            if (sep) {
                sb.append(", ");
            } else {
                sep = true;
            }
            if (arg == null) {
                sb.append("null");
            } else {
                sb.append(arg.getClass().getName());
                sb.append(":");
                sb.append(arg);
            }
        }
        return sb.toString();
    }

}