com.haulmont.bali.util.ReflectionHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.bali.util.ReflectionHelper.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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.haulmont.bali.util;

import org.apache.commons.lang.reflect.ConstructorUtils;
import org.dom4j.Element;

import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.*;

/**
 * Utility class to simplify work with Java reflection.
 *
 */
public final class ReflectionHelper {

    private ReflectionHelper() {
    }

    /**
     * Load class by name.
     * @param name  class FQN or primitive type name
     * @return      class instance
     * @throws ClassNotFoundException if not found
     */
    public static Class<?> loadClass(String name) throws ClassNotFoundException {
        switch (name) {
        case "int":
            return int.class;
        case "short":
            return short.class;
        case "char":
            return char.class;
        case "byte":
            return byte.class;
        case "long":
            return long.class;
        case "float":
            return float.class;
        case "double":
            return double.class;
        case "boolean":
            return boolean.class;
        }
        return Thread.currentThread().getContextClassLoader().loadClass(name);
    }

    /**
     * Load class by name, wrapping a {@link ClassNotFoundException} into unchecked exception.
     * @param name  class FQN
     * @return      class instance
     */
    public static <T> Class<T> getClass(String name) {
        try {
            return (Class<T>) loadClass(name);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Instantiates an object by appropriate constructor.
     * @param cls       class
     * @param params    constructor arguments
     * @return          created object instance
     * @throws NoSuchMethodException    if the class has no constructor matching the given arguments
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(Class<T> cls, Object... params) throws NoSuchMethodException {
        Class[] paramTypes = getParamTypes(params);

        Constructor<T> constructor = ConstructorUtils.getMatchingAccessibleConstructor(cls, paramTypes);
        if (constructor == null)
            throw new NoSuchMethodException(
                    "Cannot find a matching constructor for " + cls.getName() + " and given parameters");
        try {
            return constructor.newInstance(params);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Searches for a method by its name and arguments.
     * @param c         class
     * @param name      method name
     * @param params    method arguments
     * @return          method reference or null if a suitable method not found
     */
    @Nullable
    public static Method findMethod(Class c, String name, Object... params) {
        Class[] paramTypes = getParamTypes(params);

        Method method = null;
        try {
            method = c.getDeclaredMethod(name, paramTypes);
        } catch (NoSuchMethodException e) {
            try {
                method = c.getMethod(name, paramTypes);
            } catch (NoSuchMethodException e1) {
                //
            }
        }
        if (method != null)
            method.setAccessible(true);

        return method;
    }

    /**
     * Invokes a method by reflection.
     * @param obj       object instance
     * @param name      method name
     * @param params    method arguments
     * @return          method result
     * @throws NoSuchMethodException if a suitable method not found
     */
    public static <T> T invokeMethod(Object obj, String name, Object... params) throws NoSuchMethodException {
        Class[] paramTypes = getParamTypes(params);

        final Class<?> aClass = obj.getClass();
        Method method;
        try {
            method = aClass.getDeclaredMethod(name, paramTypes);
        } catch (NoSuchMethodException e) {
            method = aClass.getMethod(name, paramTypes);
        }
        method.setAccessible(true);
        try {
            //noinspection unchecked
            return (T) method.invoke(obj, params);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Constructs an array of argument types from an array of actual values. Values can not contain nulls.
     * @param params    arguments
     * @return          the array of argument types
     */
    public static Class[] getParamTypes(Object... params) {
        List<Class> paramClasses = new ArrayList<>();
        for (Object param : params) {
            if (param == null)
                throw new IllegalStateException("Null parameter");

            final Class aClass = param.getClass();
            if (List.class.isAssignableFrom(aClass)) {
                paramClasses.add(List.class);
            } else if (Set.class.isAssignableFrom(aClass)) {
                paramClasses.add(Set.class);
            } else if (Map.class.isAssignableFrom(aClass)) {
                paramClasses.add(Map.class);
            } else if (Element.class.isAssignableFrom(aClass)) {
                paramClasses.add(Element.class);
            } else {
                paramClasses.add(aClass);
            }
        }
        return paramClasses.toArray(new Class<?>[paramClasses.size()]);
    }
}