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

org.infinispan.cdi.common.util.Reflections Maven / Gradle / Ivy

The newest version!
package org.infinispan.cdi.common.util;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashSet;
import java.util.Set;

import jakarta.enterprise.inject.spi.Annotated;
import jakarta.enterprise.inject.spi.BeanManager;

/**
 * Utility class for working with JDK Reflection and also CDI's
 * {@link Annotated} metadata.
 *
 * @author Stuart Douglas
 * @author Pete Muir
 */
public class Reflections {

    /**
     * An empty array of type {@link Annotation}, useful converting lists to
     * arrays.
     */
    public static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];

    /**
     * An empty array of type {@link Object}, useful for converting lists to
     * arrays.
     */
    public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];

    public static final Type[] EMPTY_TYPES = {};

    public static final Class[] EMPTY_CLASSES = new Class[0];

    /**
     * 

* Perform a runtime cast. Similar to {@link Class#cast(Object)}, but useful * when you do not have a {@link Class} object for type you wish to cast to. *

*

*

* {@link Class#cast(Object)} should be used if possible *

* * @param the type to cast to * @param obj the object to perform the cast on * @return the casted object * @throws ClassCastException if the type T is not a subtype of the object * @see Class#cast(Object) */ @SuppressWarnings("unchecked") public static T cast(Object obj) { return (T) obj; } /** * Get all the declared methods on the class hierarchy. This will * return overridden methods. * * @param clazz The class to search * @return the set of all declared methods or an empty set if there are none */ public static Set getAllDeclaredMethods(Class clazz) { HashSet methods = new HashSet(); for (Class c = clazz; c != null && c != Object.class; c = c.getSuperclass()) { for (Method a : c.getDeclaredMethods()) { methods.add(a); } } return methods; } private static String buildInvokeMethodErrorMessage(Method method, Object obj, Object... args) { StringBuilder message = new StringBuilder(String.format("Exception invoking method [%s] on object [%s], using arguments [", method.getName(), obj)); if (args != null) for (int i = 0; i < args.length; i++) message.append((i > 0 ? "," : "") + args[i]); message.append("]"); return message.toString(); } /** * Set the accessibility flag on the {@link AccessibleObject} as described in * {@link AccessibleObject#setAccessible(boolean)} within the context of * a {@link PrivilegedAction}. * * @param member the accessible object type * @param member the accessible object * @return the accessible object after the accessible flag has been altered */ public static A setAccessible(A member) { AccessController.doPrivileged(new SetAccessiblePrivilegedAction(member)); return member; } /** *

* Invoke the specified method on the provided instance, passing any additional * arguments included in this method as arguments to the specified method. *

*

*

* This method attempts to set the accessible flag of the method in a * {@link PrivilegedAction} before invoking the method if the first argument * is true. *

*

*

This method provides the same functionality and throws the same exceptions as * {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the * expected return type set to {@link Object}.

* * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...) * @see Method#invoke(Object, Object...) */ public static Object invokeMethod(boolean setAccessible, Method method, Object instance, Object... args) { return invokeMethod(setAccessible, method, Object.class, instance, args); } /** *

* Invoke the specified method on the provided instance, passing any additional * arguments included in this method as arguments to the specified method. *

*

*

This method provides the same functionality and throws the same exceptions as * {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the * expected return type set to {@link Object} and honoring the accessibility of * the method.

* * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...) * @see Method#invoke(Object, Object...) */ public static T invokeMethod(Method method, Class expectedReturnType, Object instance, Object... args) { return invokeMethod(false, method, expectedReturnType, instance, args); } /** *

* Invoke the method on the instance, with any arguments specified, casting * the result of invoking the method to the expected return type. *

*

*

* This method wraps {@link Method#invoke(Object, Object...)}, converting the * checked exceptions that {@link Method#invoke(Object, Object...)} specifies * to runtime exceptions. *

*

*

* If instructed, this method attempts to set the accessible flag of the method in a * {@link PrivilegedAction} before invoking the method. *

* * @param setAccessible flag indicating whether method should first be set as * accessible * @param method the method to invoke * @param instance the instance to invoke the method * @param args the arguments to the method * @return the result of invoking the method, or null if the method's return * type is void * @throws RuntimeException if this Method object enforces Java * language access control and the underlying method is * inaccessible or if the underlying method throws an exception or * if the initialization provoked by this method fails. * @throws IllegalArgumentException if the method is an instance method and * the specified instance argument is not an instance * of the class or interface declaring the underlying method (or * of a subclass or implementor thereof); if the number of actual * and formal parameters differ; if an unwrapping conversion for * primitive arguments fails; or if, after possible unwrapping, a * parameter value cannot be converted to the corresponding formal * parameter type by a method invocation conversion. * @throws NullPointerException if the specified instance is * null and the method is an instance method. * @throws ClassCastException if the result of invoking the method cannot be * cast to the expectedReturnType * @throws ExceptionInInitializerError if the initialization provoked by this * method fails. * @see Method#invoke(Object, Object...) */ public static T invokeMethod(boolean setAccessible, Method method, Class expectedReturnType, Object instance, Object... args) { if (setAccessible && !method.isAccessible()) { setAccessible(method); } try { return expectedReturnType.cast(method.invoke(instance, args)); } catch (IllegalAccessException ex) { throw new RuntimeException(buildInvokeMethodErrorMessage(method, instance, args), ex); } catch (IllegalArgumentException ex) { throw new IllegalArgumentException(buildInvokeMethodErrorMessage(method, instance, args), ex); } catch (InvocationTargetException ex) { throw new RuntimeException(buildInvokeMethodErrorMessage(method, instance, args), ex.getCause()); } catch (NullPointerException ex) { NullPointerException ex2 = new NullPointerException(buildInvokeMethodErrorMessage(method, instance, args)); ex2.initCause(ex.getCause()); throw ex2; } catch (ExceptionInInitializerError e) { ExceptionInInitializerError e2 = new ExceptionInInitializerError(buildInvokeMethodErrorMessage(method, instance, args)); e2.initCause(e.getCause()); throw e2; } } private static String buildGetFieldValueErrorMessage(Field field, Object obj) { return String.format("Exception reading [%s] field from object [%s].", field.getName(), obj); } /** *

* Get the value of the field, on the specified instance, casting the value * of the field to the expected type. *

*

*

* This method wraps {@link Field#get(Object)}, converting the checked * exceptions that {@link Field#get(Object)} specifies to runtime exceptions. *

* * @param the type of the field's value * @param field the field to operate on * @param instance the instance from which to retrieve the value * @param expectedType the expected type of the field's value * @return the value of the field * @throws RuntimeException if the underlying field is inaccessible. * @throws IllegalArgumentException if the specified instance is not an * instance of the class or interface declaring the underlying * field (or a subclass or implementor thereof). * @throws NullPointerException if the specified instance is null and the field * is an instance field. * @throws ExceptionInInitializerError if the initialization provoked by this * method fails. */ public static T getFieldValue(Field field, Object instance, Class expectedType) { try { return Reflections.cast(field.get(instance)); } catch (IllegalAccessException e) { throw new RuntimeException(buildGetFieldValueErrorMessage(field, instance), e); } catch (NullPointerException ex) { NullPointerException ex2 = new NullPointerException(buildGetFieldValueErrorMessage(field, instance)); ex2.initCause(ex.getCause()); throw ex2; } catch (ExceptionInInitializerError e) { ExceptionInInitializerError e2 = new ExceptionInInitializerError(buildGetFieldValueErrorMessage(field, instance)); e2.initCause(e.getCause()); throw e2; } } /** * Extract the raw type, given a type. * * @param the type * @param type the type to extract the raw type from * @return the raw type, or null if the raw type cannot be determined. */ @SuppressWarnings("unchecked") public static Class getRawType(Type type) { if (type instanceof Class) { return (Class) type; } else if (type instanceof ParameterizedType) { if (((ParameterizedType) type).getRawType() instanceof Class) { return (Class) ((ParameterizedType) type).getRawType(); } } return null; } /** * Check if a class is serializable. * * @param clazz The class to check * @return true if the class implements serializable or is a primitive */ public static boolean isSerializable(Class clazz) { return clazz.isPrimitive() || Serializable.class.isAssignableFrom(clazz); } /** * Check the assignability of one type to another, taking into account the * actual type arguements * * @param rawType1 the raw type of the class to check * @param actualTypeArguments1 the actual type arguements to check, or an * empty array if not a parameterized type * @param rawType2 the raw type of the class to check * @param actualTypeArguments2 the actual type arguements to check, or an * empty array if not a parameterized type * @return */ public static boolean isAssignableFrom(Class rawType1, Type[] actualTypeArguments1, Class rawType2, Type[] actualTypeArguments2) { return Types.boxedClass(rawType1).isAssignableFrom(Types.boxedClass(rawType2)) && isAssignableFrom(actualTypeArguments1, actualTypeArguments2); } public static boolean matches(Class rawType1, Type[] actualTypeArguments1, Class rawType2, Type[] actualTypeArguments2) { return Types.boxedClass(rawType1).equals(Types.boxedClass(rawType2)) && isAssignableFrom(actualTypeArguments1, actualTypeArguments2); } public static boolean isAssignableFrom(Type[] actualTypeArguments1, Type[] actualTypeArguments2) { for (int i = 0; i < actualTypeArguments1.length; i++) { Type type1 = actualTypeArguments1[i]; Type type2 = Object.class; if (actualTypeArguments2.length > i) { type2 = actualTypeArguments2[i]; } if (!isAssignableFrom(type1, type2)) { return false; } } return true; } public static boolean matches(Type type1, Set types2) { for (Type type2 : types2) { if (matches(type1, type2)) { return true; } } return false; } public static boolean isAssignableFrom(Type type1, Type[] types2) { for (Type type2 : types2) { if (isAssignableFrom(type1, type2)) { return true; } } return false; } public static boolean isAssignableFrom(Type type1, Type type2) { if (type1 instanceof Class) { Class clazz = (Class) type1; if (isAssignableFrom(clazz, EMPTY_TYPES, type2)) { return true; } } if (type1 instanceof ParameterizedType) { ParameterizedType parameterizedType1 = (ParameterizedType) type1; if (parameterizedType1.getRawType() instanceof Class) { if (isAssignableFrom((Class) parameterizedType1.getRawType(), parameterizedType1.getActualTypeArguments(), type2)) { return true; } } } if (type1 instanceof WildcardType) { WildcardType wildcardType = (WildcardType) type1; if (isTypeBounded(type2, wildcardType.getLowerBounds(), wildcardType.getUpperBounds())) { return true; } } if (type2 instanceof WildcardType) { WildcardType wildcardType = (WildcardType) type2; if (isTypeBounded(type1, wildcardType.getUpperBounds(), wildcardType.getLowerBounds())) { return true; } } if (type1 instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) type1; if (isTypeBounded(type2, EMPTY_TYPES, typeVariable.getBounds())) { return true; } } if (type2 instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) type2; if (isTypeBounded(type1, typeVariable.getBounds(), EMPTY_TYPES)) { return true; } } return false; } public static boolean matches(Type type1, Type type2) { if (type1 instanceof Class) { Class clazz = (Class) type1; if (matches(clazz, EMPTY_TYPES, type2)) { return true; } } if (type1 instanceof ParameterizedType) { ParameterizedType parameterizedType1 = (ParameterizedType) type1; if (parameterizedType1.getRawType() instanceof Class) { if (matches((Class) parameterizedType1.getRawType(), parameterizedType1.getActualTypeArguments(), type2)) { return true; } } } if (type1 instanceof WildcardType) { WildcardType wildcardType = (WildcardType) type1; if (isTypeBounded(type2, wildcardType.getLowerBounds(), wildcardType.getUpperBounds())) { return true; } } if (type2 instanceof WildcardType) { WildcardType wildcardType = (WildcardType) type2; if (isTypeBounded(type1, wildcardType.getUpperBounds(), wildcardType.getLowerBounds())) { return true; } } if (type1 instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) type1; if (isTypeBounded(type2, EMPTY_TYPES, typeVariable.getBounds())) { return true; } } if (type2 instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) type2; if (isTypeBounded(type1, typeVariable.getBounds(), EMPTY_TYPES)) { return true; } } return false; } public static boolean isTypeBounded(Type type, Type[] lowerBounds, Type[] upperBounds) { if (lowerBounds.length > 0) { if (!isAssignableFrom(type, lowerBounds)) { return false; } } if (upperBounds.length > 0) { if (!isAssignableFrom(upperBounds, type)) { return false; } } return true; } public static boolean isAssignableFrom(Class rawType1, Type[] actualTypeArguments1, Type type2) { if (type2 instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type2; if (parameterizedType.getRawType() instanceof Class) { if (isAssignableFrom(rawType1, actualTypeArguments1, (Class) parameterizedType.getRawType(), parameterizedType.getActualTypeArguments())) { return true; } } } else if (type2 instanceof Class) { Class clazz = (Class) type2; if (isAssignableFrom(rawType1, actualTypeArguments1, clazz, EMPTY_TYPES)) { return true; } } else if (type2 instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) type2; if (isTypeBounded(rawType1, actualTypeArguments1, typeVariable.getBounds())) { return true; } } return false; } public static boolean matches(Class rawType1, Type[] actualTypeArguments1, Type type2) { if (type2 instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type2; if (parameterizedType.getRawType() instanceof Class) { if (matches(rawType1, actualTypeArguments1, (Class) parameterizedType.getRawType(), parameterizedType.getActualTypeArguments())) { return true; } } } else if (type2 instanceof Class) { Class clazz = (Class) type2; if (matches(rawType1, actualTypeArguments1, clazz, EMPTY_TYPES)) { return true; } } return false; } /** * Check whether whether any of the types1 matches a type in types2 * * @param types1 * @param types2 * @return */ public static boolean matches(Set types1, Set types2) { for (Type type : types1) { if (matches(type, types2)) { return true; } } return false; } public static boolean isAssignableFrom(Type[] types1, Type type2) { for (Type type : types1) { if (isAssignableFrom(type, type2)) { return true; } } return false; } private Reflections() { } /** * Inspects an annotated element for the given meta annotation. This should * only be used for user defined meta annotations, where the annotation must * be physically present. * * @param element The element to inspect * @param annotationType The meta annotation to search for * @return The annotation instance found on this element or null if no * matching annotation was found. */ public static
A getMetaAnnotation(Annotated element, final Class annotationType) { for (Annotation annotation : element.getAnnotations()) { if (annotation.annotationType().isAnnotationPresent(annotationType)) { return annotation.annotationType().getAnnotation(annotationType); } } return null; } /** * Extract the qualifiers from a set of annotations. * * @param beanManager the beanManager to use to determine if an annotation is * a qualifier * @param annotations the annotations to check * @return any qualifiers present in annotations */ @SuppressWarnings("unchecked") public static Set getQualifiers(BeanManager beanManager, Iterable annotations) { return getQualifiers(beanManager, new Iterable[]{annotations}); } /** * Extract the qualifiers from a set of annotations. * * @param beanManager the beanManager to use to determine if an annotation is * a qualifier * @param annotations the annotations to check * @return any qualifiers present in annotations */ public static Set getQualifiers(BeanManager beanManager, Iterable... annotations) { Set qualifiers = new HashSet(); for (Iterable annotationSet : annotations) { for (Annotation annotation : annotationSet) { if (beanManager.isQualifier(annotation.annotationType())) { qualifiers.add(annotation); } } } return qualifiers; } /** * Get all the declared fields on the class hierarchy. This will * return overridden fields. * * @param clazz The class to search * @return the set of all declared fields or an empty set if there are none */ public static Set getAllDeclaredFields(Class clazz) { HashSet fields = new HashSet(); for (Class c = clazz; c != null && c != Object.class; c = c.getSuperclass()) { for (Field a : c.getDeclaredFields()) { fields.add(a); } } return fields; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy