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

com.linkare.zas.aspectj.utils.ReflectionUtils Maven / Gradle / Ivy

package com.linkare.zas.aspectj.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.linkare.zas.api.IConstructorSignature;
import com.linkare.zas.api.IFieldSignature;
import com.linkare.zas.api.IJoinPoint;
import com.linkare.zas.api.IMethodSignature;

/**
 * This class provides some static useful methods related to reflection based code.
 * 
 * @author Paulo Zenida
 * 
 */
public class ReflectionUtils {

    private static final String EMPTY_STRING = "";

    private static final String COMMA = ",";

    private static final String END_ARRAY_TYPE_PATTERN = ";";

    private static final String BEGIN_ARRAY_TYPE_PATTERN = "[L";

    private static final String OPEN_ARRAY_PATTERN = "[";

    private static final String ARRAY_PATTERN = "[]";

    private static final String DOLLAR = "$";

    private static final String DOT = ".";

    /**
     * 
     * @param argTypesNames
     *            The arguments types names from the method or constructor.
     * @return It returns the array of classes from the argTypesNames passed as a parameter.
     * @throws ClassNotFoundException
     */
    public static final Class[] buildParameterTypesFrom(final String argTypesNames) throws ClassNotFoundException {
	if (argTypesNames == null)
	    return null;
	if (argTypesNames.length() == 0)
	    return new Class[] {};
	final String[] args = argTypesNames.split(COMMA);
	final Class[] result = new Class[args.length];
	for (int i = 0; i < args.length; i++) {
	    try {
		String type = args[i].trim();
		final boolean isArray = isArray(type);
		if (isArray) {
		    type = getTypeFromArray(type);
		}
		final PrimitiveType primitiveType = PrimitiveType.getPrimitive(type);
		if (primitiveType != null) {
		    primitiveType.setArrayType(isArray);
		    result[i] = primitiveType.getPrimitiveTypeClass();
		} else {
		    if (isArray) {
			type = BEGIN_ARRAY_TYPE_PATTERN + type + END_ARRAY_TYPE_PATTERN;
		    }
		    result[i] = Class.forName(type);
		}
	    } catch (ClassNotFoundException e) {
		result[i] = tryToInstantiateIfInnerClass(args[i]);
	    }
	}
	return result;
    }

    /**
     * 
     * @param type
     *            The name of the type. E.g., java.lang.String.
     * @return It returns true if the pattern "[]" is found on the type passed in as a parameter. It returns false otherwise.
     */
    private static boolean isArray(final String type) {
	if (type.endsWith(ARRAY_PATTERN))
	    return true;
	return false;
    }

    /**
     * 
     * @param type
     *            The name of the type. E.g., java.lang.String[].
     * @return It returns the class type from the array type name passed in as a parameter.
     * 
     */
    private static String getTypeFromArray(final String type) {
	if (type.indexOf(OPEN_ARRAY_PATTERN) != -1)
	    return type.substring(0, type.indexOf(OPEN_ARRAY_PATTERN));
	return type;
    }

    /**
     * 
     * @param signature
     *            The signature of the class.
     * @return It returns the instantiated class if the signature is one from an inner class.
     * @throws ClassNotFoundException
     */
    private static Class tryToInstantiateIfInnerClass(final String signature) throws ClassNotFoundException {
	String innerClassName = signature;
	while (innerClassName.lastIndexOf(DOT) != -1) {
	    int indexOfLastDot = innerClassName.lastIndexOf(DOT);
	    innerClassName = innerClassName.substring(0, indexOfLastDot) + DOLLAR + innerClassName.substring(indexOfLastDot + 1);
	    try {
		Class innerClass = Class.forName(innerClassName);
		return innerClass;
	    } catch (ClassNotFoundException e) {
	    }
	}
	throw new ClassNotFoundException();
    }

    /**
     * 
     * @author Paulo Zenida
     * 
     */
    public enum PrimitiveType {

	BOOLEAN(false),

	BYTE(false),

	INT(false),

	FLOAT(false),

	DOUBLE(false),

	SHORT(false),

	LONG(false),

	CHAR(false);

	private static final String THERE_IS_NO_CLASS_FOR_THIS_PRIMITIVE_TYPE = "There is no class for this primitive type: ";

	private boolean isArrayType;

	/**
	 * 
	 * @param isArrayType
	 *            The flat to control if the primitive type is an array.
	 */
	private PrimitiveType(final boolean isArrayType) {
	}

	/**
	 * 
	 * @param type
	 * @return Returns the primitive type if the type if of a primitive type. Returns null otherwise.
	 */
	public static PrimitiveType getPrimitive(final String type) {
	    for (PrimitiveType primitiveType : values()) {
		if (type.equals(primitiveType.toString()))
		    return primitiveType;
	    }
	    return null;
	}

	/**
	 * 
	 * @return Returns the wrapper class for this primitive type.
	 */
	public Class getPrimitiveTypeClass() {
	    switch (this) {
	    case BOOLEAN:
		if (isArrayType())
		    return boolean[].class;
		return Boolean.TYPE;
	    case BYTE:
		if (isArrayType())
		    return byte[].class;
		return Byte.TYPE;
	    case INT:
		if (isArrayType())
		    return int[].class;
		return Integer.TYPE;
	    case FLOAT:
		if (isArrayType())
		    return float[].class;
		return Float.TYPE;
	    case DOUBLE:
		if (isArrayType())
		    return double[].class;
		return Double.TYPE;
	    case SHORT:
		if (isArrayType())
		    return short[].class;
		return Short.TYPE;
	    case LONG:
		if (isArrayType())
		    return long[].class;
		return Long.TYPE;
	    case CHAR:
		if (isArrayType())
		    return char[].class;
		return Character.TYPE;
	    }
	    throw new RuntimeException(THERE_IS_NO_CLASS_FOR_THIS_PRIMITIVE_TYPE + this);
	}

	/**
	 * @return the isArrayType
	 */
	private boolean isArrayType() {
	    return isArrayType;
	}

	/**
	 * @param isArrayType
	 *            the isArrayType to set
	 */
	private void setArrayType(boolean isArrayType) {
	    this.isArrayType = isArrayType;
	}

	@Override
	public String toString() {
	    switch (this) {
	    case BOOLEAN:
	    case BYTE:
	    case INT:
	    case FLOAT:
	    case DOUBLE:
	    case SHORT:
	    case LONG:
	    case CHAR:
		return this.name().toLowerCase();
	    }
	    return EMPTY_STRING;
	}
    }

    /**
     * @param clazz
     * @param methodName
     * @param methodArgs
     * @return It returns the declared method (either public, protected, package-private, or private) in a given class or any of its superclasses. The method is
     *         used since the getMethod() from the Java API does not return non public methods and getDeclaredMethod() does not return them recursively.
     * @throws NoSuchMethodException
     */
    public static Method getDeclaredMethodRecursive(Class clazz, String methodName, Class[] methodArgs) throws NoSuchMethodException {
	try {
	    Method m = clazz.getDeclaredMethod(methodName, methodArgs);
	    return m;
	} catch (NoSuchMethodException e) {
	    if (clazz != Object.class)
		return getDeclaredMethodRecursive(clazz.getSuperclass(), methodName, methodArgs);
	}

	throw new NoSuchMethodException(methodName + "(" + Arrays.deepToString(methodArgs) + ")");
    }

    /**
     * @param clazz
     * @param methodArgs
     * @return It returns the declared constructor (either public, protected, package-private, or private) in a given class or any of its superclasses. The
     *         method is used since the getConstructor() from the Java API does not return non public methods and getDeclaredConstructor() does not return them
     *         recursively.
     * @throws NoSuchMethodException
     */
    public static Constructor getDeclaredConstructorRecursive(Class clazz, Class[] methodArgs) throws NoSuchMethodException {
	try {
	    Constructor c = clazz.getDeclaredConstructor(methodArgs);
	    return c;
	} catch (NoSuchMethodException e) {
	    if (clazz != Object.class)
		return getDeclaredConstructorRecursive(clazz.getSuperclass(), methodArgs);
	}

	throw new NoSuchMethodException("(" + Arrays.deepToString(methodArgs) + ")");
    }

    /**
     * 
     * @param clazz
     * @param fieldName
     * @return It returns the declared field (either public, protected, package-private, or private) in a given class or any of its super classes. The method is
     *         used since the getField() from the Java API does not return non public fields and getDeclaredField() does not return them recursively.
     * @throws NoSuchFieldException
     */
    public static Field getDeclaredFieldRecursive(Class clazz, String fieldName) throws NoSuchFieldException {
	try {
	    Field f = clazz.getDeclaredField(fieldName);
	    return f;
	} catch (NoSuchFieldException e) {
	    if (clazz != Object.class)
		return getDeclaredFieldRecursive(clazz.getSuperclass(), fieldName);
	}

	throw new NoSuchFieldException(fieldName);
    }

    /**
     * 
     * @param method
     *            The method to check if it is overriding the corresponding method declared on a parent type.
     * @return Returns true if this method overrides another one. Returns false otherwise.
     */
    public static boolean isMethodOverridden(final Method method) {
	if (method != null) {
	    Method superM;
	    try {
		superM = getDeclaredMethodRecursive(method.getDeclaringClass().getSuperclass(), method.getName(), method.getParameterTypes());
		return superM != null && superM.getDeclaringClass() != method.getDeclaringClass();
	    } catch (NoSuchMethodException e) {
		return false;
	    }
	}
	return false;
    }

    /**
     * 
     * @param method
     *            The method whose equivalent methods are to be searched for.
     * @return Returns a list of all methods which are equivalent to the method passed in as argument, in the method's type hierarchy.
     */
    public static List getEquivalentMethodsInTheHierarchy(final Method method) {
	final List result = new ArrayList();
	if (method == null) {
	    return result;
	}
	result.add(method);
	Method superMethod = null;
	try {
	    superMethod = getDeclaredMethodRecursive(method.getDeclaringClass().getSuperclass(), method.getName(), method.getParameterTypes());
	} catch (NoSuchMethodException e) {
	}
	if (superMethod != null && (superMethod.getDeclaringClass() != Object.class)) {
	    result.addAll(getEquivalentMethodsInTheHierarchy(superMethod));
	}
	return result;
    }

    /**
     * 
     * @param constructor
     *            The method whose equivalent methods are to be searched for.
     * @return Returns a list of all constructors which are equivalent to the constructor passed in as argument, in the method's type hierarchy.
     */
    public static List> getEquivalentConstructorsInTheHierarchy(final Constructor constructor) {
	final List> result = new ArrayList>();
	if (constructor == null) {
	    return result;
	}
	result.add(constructor);
	Constructor superConstructor = null;
	try {
	    superConstructor = getDeclaredConstructorRecursive(constructor.getDeclaringClass().getSuperclass(), constructor.getParameterTypes());
	} catch (NoSuchMethodException e) {
	}
	if (superConstructor != null && (superConstructor.getDeclaringClass() != Object.class)) {
	    result.addAll(getEquivalentConstructorsInTheHierarchy(superConstructor));
	}
	return result;
    }

    /**
     * 
     * @param joinPoint
     * @return Returns an instance of Method for the joinPoint passed in as argument.
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws SecurityException
     * @see Method
     */
    public static Method getMethodFrom(final IJoinPoint joinPoint) throws SecurityException, NoSuchMethodException, ClassNotFoundException {
	if (joinPoint.getKind().isMethod()) {
	    final IMethodSignature sig = (IMethodSignature) joinPoint.getSignature();
	    return sig.getMethod();
	}
	return null;
    }

    /**
     * 
     * @param joinPoint
     * @return Returns an instance of Constructor for the joinPoint passed in as argument.
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws SecurityException
     * @see Constructor
     */
    public static Constructor getConstructorFrom(final IJoinPoint joinPoint) throws SecurityException, NoSuchMethodException,
	    ClassNotFoundException {
	if (joinPoint.getKind().isConstructor()) {
	    IConstructorSignature sig = (IConstructorSignature) joinPoint.getSignature();
	    return sig.getConstructor();
	}
	return null;
    }

    /**
     * 
     * @param joinPoint
     * @return Returns an instance of Field for the joinPoint passed in as argument.
     * @throws NoSuchFieldException
     * @throws SecurityException
     * @see Field
     */
    public static Field getFieldFrom(final IJoinPoint joinPoint) throws SecurityException, NoSuchFieldException {
	if (joinPoint.getKind().isField()) {
	    IFieldSignature sig = (IFieldSignature) joinPoint.getSignature();
	    return sig.getField();
	}
	return null;
    }

    /**
     * 
     * @param method
     * @param annotationClass
     * @return Returns an instance of an Annotation declared in the method method, if the type of the annotation is equivalent to
     *         annotationClass.
     */
    public static Annotation getAnnotation(final Method method, final Class annotationClass) {
	for (final Annotation annotation : method.getDeclaredAnnotations()) {
	    if (annotation.annotationType() == annotationClass) {
		return annotation;
	    }
	}
	return null;
    }

    /**
     * 
     * @param constructor
     * @param annotationClass
     * @return Returns an instance of an Annotation declared in the constructor constructor, if the type of the annotation is
     *         equivalent to annotationClass.
     */
    public static Annotation getAnnotation(final Constructor constructor, final Class annotationClass) {
	for (final Annotation annotation : constructor.getDeclaredAnnotations()) {
	    if (annotation.annotationType() == annotationClass) {
		return annotation;
	    }
	}
	return null;
    }

    /**
     * 
     * @param field
     * @param annotationClass
     * @return Returns an instance of an Annotation declared in the field filed, if the type of the annotation is equivalent to
     *         annotationClass.
     */
    public static Annotation getAnnotation(final Field field, final Class annotationClass) {
	for (final Annotation annotation : field.getDeclaredAnnotations()) {
	    if (annotation.annotationType() == annotationClass) {
		return annotation;
	    }
	}
	return null;
    }

    /**
     * 
     * @param clazz
     * @param annotationClass
     * @return Returns an instance of an Annotation declared in the class clazz, if the type of the annotation is equivalent to
     *         annotationClass.
     */
    public static Annotation getAnnotation(final Class clazz, final Class annotationClass) {
	for (final Annotation annotation : clazz.getDeclaredAnnotations()) {
	    if (annotation.annotationType() == annotationClass) {
		return annotation;
	    }
	}
	return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy