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

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

There is a newer version: 3.1
Show newest version
/*
 * #%L
 * Nuiton Utils
 * 
 * $Id: ReflectUtil.java 2360 2012-06-11 10:24:36Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/nuiton-utils/tags/nuiton-utils-2.6.10/nuiton-utils/src/main/java/org/nuiton/util/ReflectUtil.java $
 * %%
 * Copyright (C) 2004 - 2010 CodeLutin
 * %%
 * 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%
 */

package org.nuiton.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.nuiton.i18n.I18n._;

/**
 * Introspection sur une classe. Détermine si un attribut est constant,
 * recherche de constantes d'un type donné, conversion d'une classe en
 * Enum...
 * 

* Created: 30 décembre 2007 * * @author tchemit * $Id: ReflectUtil.java 2360 2012-06-11 10:24:36Z tchemit $ */ public class ReflectUtil { /** Logger */ static private Log log = LogFactory.getLog(ReflectUtil.class); /** * Pour déterminer si un champ d'une classe est une constante * (modifiers sont static, final et public) * * @param field le champs à tester * @return true si les modifiers sont final, static et public */ public static boolean isConstantField(Field field) { int modifiers = field.getModifiers(); return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers); } /** * Recherche dans une classe donnée klazz, les constantes d'un * certain type searchingClass et les retourne. *

* L'algorithme parcourt aussi les superclasses. * * @param enumeration's type * @param klass la classe contenant les constantes * @param searchingClass le type des champs constants à récupérer * @return la liste des champs du type requis dans * @throws RuntimeException si problème lors de la récupération */ @SuppressWarnings({"unchecked"}) public static List getConstants(Class klass, Class searchingClass) { List result = new ArrayList(); for (Field field : klass.getDeclaredFields()) { if (!field.isAccessible()) { field.setAccessible(true); } if (searchingClass.isAssignableFrom(field.getType()) && isConstantField(field)) { try { result.add((T) field.get(null)); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } Class superClass = klass.getSuperclass(); if (superClass != null) { result.addAll(getConstants(superClass, searchingClass)); } return result; } /** * @param enumeration's type * @param klass the required class * @param fieldName the required constant name * @return the constant value */ @SuppressWarnings({"unchecked"}) public static T getConstant(Class klass, String fieldName) { try { T result = null; Field f = klass.getDeclaredField(fieldName); if (isConstantField(f)) { f.setAccessible(true); result = (T) f.get(null); } return result; } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Convertit une classe non typée, en une classe d'enum * * @param enumeration's type * @param type la classe a typer * @return la classe typee * @throws IllegalArgumentException si le type est null ou non une extension * de la classe Enum. */ @SuppressWarnings({"unchecked"}) public static > Class getEnumClass(Class type) throws IllegalArgumentException { if (type == null) { throw new IllegalArgumentException(_("nuitonutil.error.null.parameter", "type")); } if (!type.isEnum()) { throw new IllegalArgumentException(_("nuitonutil.error.not.an.enum", type)); } return (Class) type; } /** * 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; } /** * 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 the unboxed type of any incoming type. *

* If incoming type is a primitive type, then just returns himself. * * @param type the type to unbox * @return the unboxed type * @see Class#isPrimitive() * @since 1.3.1 */ public static Class unboxType(Class type) { if (type.isPrimitive()) { return type; } if (Boolean.class.equals(type)) { return boolean.class; } if (Character.class.equals(type)) { return char.class; } if (Byte.class.equals(type)) { return byte.class; } if (Short.class.equals(type)) { return short.class; } if (Integer.class.equals(type)) { return int.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; } // not a primitive type return type; } /** * Obtain all the declared fields of the given {@code objectClass} with a * deep scan inside super classes and interfaces. *

* Note: The type {@link Object} will not be scanned. * * @param objectClass the object class to scan * @return the set of all declared fields found * @since 2.0 */ public static Set getAllDeclaredFields(Class objectClass) { Set result = new HashSet(); Set> visitedClasses = new HashSet>(); try { getAllDeclaredFields(objectClass, visitedClasses, result); } finally { visitedClasses.clear(); } return result; } /** * Obtain all the declared methods of the given {@code objectClass} with a * deep scan inside super classes and interfaces. *

* Note: The type {@link Object} will not be scanned. * * @param objectClass the object class to scan * @return the set of all declared methods found * @since 2.0 */ public static Set getAllDeclaredMethods(Class objectClass) { Set result = new HashSet(); Set> visitedClasses = new HashSet>(); try { getAllDeclaredMethods(objectClass, visitedClasses, result); } finally { visitedClasses.clear(); } return result; } /** * Obtain all the fields with the given annotation type. *

* Note: This method will not scan deeply the given type * (no scan of super-classes nor interfaces). * * @param objectClass the type to scan * @param annotationClass the type of annotation to scan * @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) { Map result = getFieldAnnotation(objectClass, annotationClass, false ); return result; } /** * 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 not scan deeply the given type * (no scan of super-classes nor interfaces). * * @param objectClass the type to scan * @param annotationClass the type of annotation to scan * @param type of annotation to scan * @return the dictionnary of methods with the given annotation * @since 2.0 */ public static Map getMethodAnnotation(Class objectClass, Class annotationClass) { Map result = getMethodAnnotation(objectClass, annotationClass, false ); 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 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; } protected static void getAllDeclaredFields(Class objectClass, Set> visitedClasses, Set result) { if (visitedClasses.contains(objectClass) || Object.class.equals(objectClass)) { // already scanned // or arrives to Object.class return; } // mark as scanned visitedClasses.add(objectClass); Field[] declaredFields = objectClass.getDeclaredFields(); result.addAll(Arrays.asList(declaredFields)); Class superclass = objectClass.getSuperclass(); if (superclass != null) { // scan also the superclass getAllDeclaredFields(superclass, visitedClasses, result ); } Class[] interfaces = objectClass.getInterfaces(); for (Class anInterface : interfaces) { // scan also the interface getAllDeclaredFields(anInterface, visitedClasses, result ); } } protected static void getAllDeclaredMethods(Class objectClass, Set> visitedClasses, Set result) { if (visitedClasses.contains(objectClass) || Object.class.equals(objectClass)) { // already scanned // or arrives to Object.class return; } // mark as scanned visitedClasses.add(objectClass); Method[] declaredFields = objectClass.getDeclaredMethods(); result.addAll(Arrays.asList(declaredFields)); Class superclass = objectClass.getSuperclass(); if (superclass != null) { // scan also the superclass getAllDeclaredMethods(superclass, visitedClasses, result ); } Class[] interfaces = objectClass.getInterfaces(); for (Class anInterface : interfaces) { // scan also the interface getAllDeclaredMethods(anInterface, visitedClasses, 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 - 2025 Weber Informatics LLC | Privacy Policy