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

org.nuiton.jaxx.runtime.util.ReflectUtil Maven / Gradle / Ivy

There is a newer version: 3.1.5
Show newest version
package org.nuiton.jaxx.runtime.util;

/*-
 * #%L
 * JAXX :: Runtime
 * %%
 * Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

/**
 * Created by tchemit on 12/07/17.
 *
 * @author Tony Chemit - [email protected]
 */
public class ReflectUtil {

    /** Logger. */
    private static final Logger log = LogManager.getLogger(ReflectUtil.class);

    /**
     * Cherche une methode selon son nom et ses paramètres d'invocation.
     *
     * @param klass      la classe dans laquelle rechercher la méthode
     * @param methodName le nom de la méthode recherchée
     * @param strict     un drapeau pour déclancher une exception si la méthode
     *                   n'est pas trouvée
     * @param arguments  les arguments d'invocation de la méthode
     * @return la méthode trouvée
     * @throws IllegalArgumentException si la méthode n'est pas trouvée et que
     *                                  le drapeau {@code strict} est à {@code true}
     * @since 1.3.1
     */
    public static Method getDeclaredMethod(Class klass,
                                           String methodName,
                                           boolean strict,
                                           Object... arguments) throws IllegalArgumentException {
        HashSet> classes = new HashSet>();
        Method method;
        try {
            method = getDeclaredMethod(klass, methodName, classes, arguments);
        } finally {
            if (log.isDebugEnabled()) {
                log.debug("Inspected classes : " + classes);
            }
            classes.clear();
        }
        if (method == null && strict) {
            throw new IllegalArgumentException(
                    "could not find method " + methodName + " on type " +
                            klass.getName());
        }

        return method;
    }

    protected static Method getDeclaredMethod(Class klass,
                                              String methodName,
                                              Set> visitedClasses,
                                              Object... arguments) {
        if (visitedClasses.contains(klass)) {

            // this means class was already unsucessfull visited
            return null;
        }
        visitedClasses.add(klass);
        Method method = null;
        for (Method m : klass.getDeclaredMethods()) {
            if (!methodName.equals(m.getName())) {
                continue;
            }

            // same method name

            Class[] types = m.getParameterTypes();
            if (arguments.length != types.length) {
                continue;
            }

            // same number arguments

            Class[] prototype = m.getParameterTypes();
            if (log.isDebugEnabled()) {
                log.debug("Found a method with same parameters size : " +
                                  m.getName() + " : " + Arrays.toString(prototype));
            }
            int index = 0;
            boolean parametersMatches = true;
            for (Object argument : arguments) {
                Class type = prototype[index++];
                if (argument == null) {

                    // can not say anything, let says it is ok...
                    continue;
                }
                Class runtimeType = argument.getClass();
                if (log.isDebugEnabled()) {
                    log.debug("Test parameter [" + (index - 1) + "] : " +
                                      type + " vs  " + runtimeType);
                }

                type = boxType(type);
                runtimeType = boxType(runtimeType);

                if (!type.equals(runtimeType) &&
                        !type.isAssignableFrom(runtimeType)) {

                    // not same type
                    parametersMatches = false;
                    if (log.isDebugEnabled()) {
                        log.debug("Types are not matching.");
                    }
                    break;
                }
            }
            if (parametersMatches) {

                // same parameters types, this is a match
                method = m;
            }
            break;
        }
        if (method == null) {

            // try on super class
            if (klass.getSuperclass() != null) {
                method = getDeclaredMethod(klass.getSuperclass(),
                                           methodName,
                                           visitedClasses,
                                           arguments
                );
            }
        }

        if (method == null) {

            // try on interfaces
            Class[] interfaces = klass.getInterfaces();
            for (Class anInterface : interfaces) {
                method = getDeclaredMethod(anInterface,
                                           methodName,
                                           visitedClasses,
                                           arguments
                );
                if (method != null) {
                    break;
                }
            }
        }
        return method;

    }

    /**
     * Obtain the boxed type of any incoming type.
     * 

* If incoming type is not a primitive type, then just returns himself. * * @param type the type to box * @return the boxed type * @see Class#isPrimitive() * @since 1.3.1 */ public static Class boxType(Class type) { if (!type.isPrimitive()) { return type; } if (boolean.class.equals(type)) { return Boolean.class; } if (char.class.equals(type)) { return Character.class; } if (byte.class.equals(type)) { return Byte.class; } if (short.class.equals(type)) { return Short.class; } if (int.class.equals(type)) { return Integer.class; } if (long.class.equals(type)) { return Long.class; } if (float.class.equals(type)) { return Float.class; } if (double.class.equals(type)) { return Double.class; } if (void.class.equals(type)) { return Void.class; } // should never come here... return type; } /** * Obtain all the fields with the given annotation type. *

* Note: This method will scan deeply the given type * if parameter {@code deepVisit} is setted to {@code true}. *

* Note: The type {@link Object} will not be scanned. * * @param objectClass the type to scan * @param annotationClass the type of annotation to scan * @param deepVisit flag to visit deeply the class (if set to * {@code true}, will also scan super classes * and interfaces) * @param type of annotation to scan * @return the dictionnary of fields with the given annotation * @since 2.0 */ public static Map getFieldAnnotation(Class objectClass, Class annotationClass, boolean deepVisit) { Map result = new HashMap(); Set> visitedClasses = new HashSet>(); try { getFieldAnnotation(objectClass, annotationClass, deepVisit, visitedClasses, result ); } finally { visitedClasses.clear(); } return result; } /** * Obtain all the methods with the given annotation type. * * Note: This method will scan deeply the given type * if parameter {@code deepVisit} is setted to {@code true}. * * Note: The type {@link Object} will not be scanned. * * @param objectClass the type to scan * @param annotationClass the type of annotation to scan * @param type of annotation to scan * @param deepVisit flag to visit deeply the class (if set to * {@code true}, will also scan super classes * and interfaces) * @return the dictionnary of methods with the given annotation * @since 2.0 */ public static Map getMethodAnnotation(Class objectClass, Class annotationClass, boolean deepVisit) { Map result = new HashMap(); Set> visitedClasses = new HashSet>(); try { getMethodAnnotation(objectClass, annotationClass, deepVisit, visitedClasses, result ); } finally { visitedClasses.clear(); } return result; } protected static void getFieldAnnotation(Class objectClass, Class annotationClass, boolean deepVisit, Set> visitedClasses, Map result) { if (visitedClasses.contains(objectClass) || Object.class.equals(objectClass)) { // already scanned // or arrives to Object.class return; } // mark as scanned visitedClasses.add(objectClass); for (Field field : objectClass.getDeclaredFields()) { A annotation = field.getAnnotation(annotationClass); if (annotation != null) { result.put(field, annotation); } } if (deepVisit) { Class superclass = objectClass.getSuperclass(); if (superclass != null) { // scan also the superclass getFieldAnnotation(superclass, annotationClass, deepVisit, visitedClasses, result ); } Class[] interfaces = objectClass.getInterfaces(); for (Class anInterface : interfaces) { // scan also the interface getFieldAnnotation(anInterface, annotationClass, deepVisit, visitedClasses, result ); } } } protected static void getMethodAnnotation(Class objectClass, Class annotationClass, boolean deepVisit, Set> visitedClasses, Map result) { if (visitedClasses.contains(objectClass) || Object.class.equals(objectClass)) { // already scanned // or arrives to Object.class return; } // mark as scanned visitedClasses.add(objectClass); for (Method method : objectClass.getDeclaredMethods()) { A annotation = method.getAnnotation(annotationClass); if (annotation != null) { result.put(method, annotation); } } if (deepVisit) { Class superclass = objectClass.getSuperclass(); if (superclass != null) { // scan also the superclass getMethodAnnotation(superclass, annotationClass, deepVisit, visitedClasses, result ); } Class[] interfaces = objectClass.getInterfaces(); for (Class anInterface : interfaces) { // scan also the interface getMethodAnnotation(anInterface, annotationClass, deepVisit, visitedClasses, result ); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy