| /******************************************************************************* |
| * Copyright (c) 2005, 2008 Oracle. All rights reserved. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0, which accompanies this distribution |
| * and is available at http://www.eclipse.org/legal/epl-v10.html. |
| * |
| * Contributors: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.utility.internal; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.util.Collections; |
| import java.util.Stack; |
| |
| /** |
| * Convenience methods related to the java.lang.reflect package. |
| * These methods provide shortcuts for manipulating objects via |
| * reflection; particularly when dealing with fields and/or methods that |
| * are not publicly accessible or are inherited. |
| * |
| * In most cases, all the exceptions are handled and |
| * wrapped in java.lang.RuntimeExceptions; so these methods should |
| * be used when you are confident that you will not having any problems |
| * using reflection. |
| * |
| * There are also a number of methods whose names |
| * begin with "attempt". These methods will throw a NoSuchMethodException |
| * or NoSuchFieldException when appropriate, allowing you to probe |
| * for methods that should be present but might not. |
| */ |
| public final class ClassTools { |
| |
| public static final Class<?>[] ZERO_PARAMETER_TYPES = new Class[0]; |
| public static final Object[] ZERO_PARAMETERS = new Object[0]; |
| private static final String CR = StringTools.CR; |
| |
| public static final char NESTED_CLASS_NAME_SEPARATOR = '$'; |
| |
| public static final char ARRAY_INDICATOR = '['; |
| public static final char TYPE_DECLARATION_ARRAY_OPEN = '['; |
| public static final char TYPE_DECLARATION_ARRAY_CLOSE = ']'; |
| |
| public static final char REFERENCE_CLASS_CODE = 'L'; |
| public static final char REFERENCE_CLASS_NAME_DELIMITER = ';'; |
| |
| private static Primitive[] PRIMITIVES; // pseudo-'final' - lazy-initialized |
| public static final char BYTE_CODE = 'B'; |
| public static final char CHAR_CODE = 'C'; |
| public static final char DOUBLE_CODE = 'D'; |
| public static final char FLOAT_CODE = 'F'; |
| public static final char INT_CODE = 'I'; |
| public static final char LONG_CODE = 'J'; |
| public static final char SHORT_CODE = 'S'; |
| public static final char BOOLEAN_CODE = 'Z'; |
| public static final char VOID_CODE = 'V'; |
| private static int MAX_PRIMITIVE_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized |
| private static int MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized |
| |
| public static final String VOID_CLASS_NAME = void.class.getName(); |
| public static final String VOID_WRAPPER_CLASS_NAME = java.lang.Void.class.getName(); |
| |
| |
| /** |
| * Return all the fields for the |
| * specified class, including inherited fields. |
| * Class#allFields() |
| */ |
| public static Field[] allFields(Class<?> javaClass) { |
| Stack<Field> stack = new Stack<Field>(); |
| for (Class<?> tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) { |
| pushDeclaredFields(tempClass, stack); |
| } |
| Collections.reverse(stack); |
| return stack.toArray(new Field[stack.size()]); |
| } |
| |
| /** |
| * Return all the methods for the |
| * specified class, including inherited methods. |
| * Class#allMethods() |
| */ |
| public static Method[] allMethods(Class<?> javaClass) { |
| Stack<Method> stack = new Stack<Method>(); |
| for (Class<?> tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) { |
| pushDeclaredMethods(tempClass, stack); |
| } |
| Collections.reverse(stack); |
| return stack.toArray(new Method[stack.size()]); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a new instance of the specified class, |
| * using the class's default (zero-argument) constructor. |
| * Throw an exception if the default constructor is not defined. |
| * Class#newInstance() throws NoSuchMethodException |
| */ |
| public static <T> T attemptNewInstance(Class<T> javaClass) throws NoSuchMethodException { |
| return attemptNewInstance(javaClass, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Return a new instance of the specified class, |
| * given the constructor parameter types and parameters. |
| * Throw an exception if the constructor is not defined. |
| * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException |
| */ |
| public static <T> T attemptNewInstance(Class<T> javaClass, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException { |
| try { |
| return constructor(javaClass, parameterTypes).newInstance(parameters); |
| } catch (InstantiationException ie) { |
| throw new RuntimeException(ie + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), ie); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), iae); |
| } catch (InvocationTargetException ite) { |
| throw new RuntimeException(fullyQualifiedConstructorSignature(javaClass, parameterTypes) + CR + ite.getTargetException(), ite); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Return a new instance of the specified class, |
| * given the constructor parameter type and parameter. |
| * Throw an exception if the constructor is not defined. |
| * Class#newInstance(Class<?> parameterType, Object parameter) throws NoSuchMethodException |
| */ |
| public static <T> T attemptNewInstance(Class<T> javaClass, Class<?> parameterType, Object parameter) throws NoSuchMethodException { |
| return attemptNewInstance(javaClass, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Attempt to get a field value, given the containing object and field name. |
| * Return its result. |
| * Useful for accessing private, package, or protected fields. |
| * Throw an exception if the field is not defined. |
| * Object#getFieldValue(String fieldName) throws NoSuchFieldException |
| */ |
| public static Object attemptToGetFieldValue(Object object, String fieldName) throws NoSuchFieldException { |
| try { |
| return field(object, fieldName).get(object); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + fullyQualifiedFieldName(object, fieldName), iae); |
| } |
| } |
| |
| /** |
| * Attempt to get a static field value, given the containing object and field name. |
| * Return its result. |
| * Useful for accessing private, package, or protected fields. |
| * Throw an exception if the field is not defined. |
| * Class#getStaticFieldValue(String fieldName) throws NoSuchFieldException |
| */ |
| public static Object attemptToGetStaticFieldValue(Class<?> javaClass, String fieldName) throws NoSuchFieldException { |
| try { |
| return field(javaClass, fieldName).get(null); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + fullyQualifiedFieldName(javaClass, fieldName), iae); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Attempt to execute a zero-argument method, |
| * given the receiver and method name. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteMethod(Object receiver, String methodName) throws NoSuchMethodException { |
| return attemptToExecuteMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Convenience method. |
| * Attempt to execute a method, given the receiver, |
| * method name, parameter type, and parameter. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteMethod(Object receiver, String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException { |
| return attemptToExecuteMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Attempt to execute a method, given the receiver, |
| * method name, parameter types, and parameters. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteMethod(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException { |
| return executeMethod(method(receiver, methodName, parameterTypes), receiver, parameters); |
| } |
| |
| /** |
| * Attempt to execute a method, given the receiver, |
| * method name, parameter types, and parameters. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * If the executed method throws an exception, rethrow that exception. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteMethodWithException(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) |
| throws Throwable, NoSuchMethodException |
| { |
| return executeMethodWithException(method(receiver, methodName, parameterTypes), receiver, parameters); |
| } |
| |
| /** |
| * Convenience method. |
| * Attempt to execute a zero-argument static method, |
| * given the class and method name. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * Useful for invoking private, package, or protected methods. |
| * Class#executeStaticMethod(String methodName) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName) throws NoSuchMethodException { |
| return attemptToExecuteStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Attempt to execute a static method, given the class, |
| * method name, parameter types, and parameters. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * Useful for invoking private, package, or protected methods. |
| * Class#executeStaticMethod(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException { |
| return executeStaticMethod(staticMethod(javaClass, methodName, parameterTypes), parameters); |
| } |
| |
| /** |
| * Convenience method. |
| * Attempt to execute a static method, given the class, |
| * method name, parameter type, and parameter. |
| * Return its result. |
| * Throw an exception if the method is not found. |
| * Useful for invoking private, package, or protected methods. |
| * Class#executeStaticMethod(String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException |
| */ |
| public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException { |
| return attemptToExecuteStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Attempt to set a field value, given the |
| * containing object, field name, and new field value. |
| * Useful for accessing private, package, or protected fields. |
| * Throw an exception if the field is not defined. |
| * Object#setFieldValue(String fieldName, Object fieldValue) throws NoSuchFieldException |
| */ |
| public static void attemptToSetFieldValue(Object object, String fieldName, Object fieldValue) throws NoSuchFieldException { |
| try { |
| field(object, fieldName).set(object, fieldValue); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + fullyQualifiedFieldName(object, fieldName), iae); |
| } |
| } |
| |
| /** |
| * Attempt to set a static field value, given the |
| * containing class, field name, and new field value. |
| * Useful for accessing private, package, or protected fields. |
| * Throw an exception if the field is not defined. |
| * Class#setStaticFieldValue(String fieldName, Object fieldValue) throws NoSuchFieldException |
| */ |
| public static void attemptToSetStaticFieldValue(Class<?> javaClass, String fieldName, Object fieldValue) throws NoSuchFieldException { |
| try { |
| field(javaClass, fieldName).set(null, fieldValue); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + fullyQualifiedFieldName(javaClass, fieldName), iae); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Return the default (zero-argument) constructor |
| * for the specified class. |
| * Set accessible to true, so we can access |
| * private/package/protected constructors. |
| * Class#constructor() throws NoSuchMethodException |
| */ |
| public static <T> Constructor<T> constructor(Class<T> javaClass) throws NoSuchMethodException { |
| return constructor(javaClass, ZERO_PARAMETER_TYPES); |
| } |
| |
| /** |
| * Return the constructor for the specified class |
| * and formal parameter types. |
| * Set accessible to true, so we can access |
| * private/package/protected constructors. |
| * Class#constructor(Class<?>[] parameterTypes) throws NoSuchMethodException |
| */ |
| public static <T> Constructor<T> constructor(Class<T> javaClass, Class<?>[] parameterTypes) throws NoSuchMethodException { |
| Constructor<T> constructor = javaClass.getDeclaredConstructor(parameterTypes); |
| constructor.setAccessible(true); |
| return constructor; |
| } |
| |
| /** |
| * Convenience method. |
| * Return the constructor for the specified class |
| * and formal parameter type. |
| * Set accessible to true, so we can access |
| * private/package/protected constructors. |
| * Class#constructor(Class<?> parameterType) throws NoSuchMethodException |
| */ |
| public static <T> Constructor<T> constructor(Class<T> javaClass, Class<?> parameterType) throws NoSuchMethodException { |
| return constructor(javaClass, new Class[] {parameterType}); |
| } |
| |
| /** |
| * Return the declared fields for the specified class. |
| * Set accessible to true, so we can access |
| * private/package/protected fields. |
| * Class#accessibleDeclaredFields() |
| */ |
| public static Field[] declaredFields(Class<?> javaClass) { |
| Field[] fields = javaClass.getDeclaredFields(); |
| for (Field field : fields) { |
| field.setAccessible(true); |
| } |
| return fields; |
| } |
| |
| /** |
| * Return the declared methods for the |
| * specified class. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| * Class#accessibleDeclaredMethods() |
| */ |
| public static Method[] declaredMethods(Class<?> javaClass) { |
| Method[] methods = javaClass.getDeclaredMethods(); |
| for (Method method : methods) { |
| method.setAccessible(true); |
| } |
| return methods; |
| } |
| |
| /** |
| * Return the default (zero-argument) constructor |
| * for the specified class. |
| * Set accessible to true, so we can access |
| * private/package/protected constructors. |
| * Class#defaultConstructor() |
| */ |
| public static <T> Constructor<T> defaultConstructor(Class<T> javaClass) throws NoSuchMethodException { |
| return constructor(javaClass); |
| } |
| |
| /** |
| * Return a field for the specified class and field name. |
| * If the class does not directly |
| * define the field, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected fields. |
| */ |
| public static Field field(Class<?> javaClass, String fieldName) throws NoSuchFieldException { |
| Field field = null; |
| try { |
| field = javaClass.getDeclaredField(fieldName); |
| } catch (NoSuchFieldException ex) { |
| Class<?> superclass = javaClass.getSuperclass(); |
| if (superclass == null) { |
| throw ex; |
| } |
| // recurse |
| return field(superclass, fieldName); |
| } |
| field.setAccessible(true); |
| return field; |
| } |
| |
| /** |
| * Convenience method. |
| * Return a field for the specified object and field name. |
| * If the object's class does not directly |
| * define the field, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected fields. |
| */ |
| public static Field field(Object object, String fieldName) throws NoSuchFieldException { |
| return field(object.getClass(), fieldName); |
| } |
| |
| /* |
| * Return a string representation of the specified constructor. |
| */ |
| private static String fullyQualifiedConstructorSignature(Class<?> javaClass, Class<?>[] parameterTypes) { |
| return fullyQualifiedMethodSignature(javaClass, null, parameterTypes); |
| } |
| |
| /* |
| * Return a string representation of the specified field. |
| */ |
| private static String fullyQualifiedFieldName(Class<?> javaClass, String fieldName) { |
| StringBuilder sb = new StringBuilder(200); |
| sb.append(javaClass.getName()); |
| sb.append('.'); |
| sb.append(fieldName); |
| return sb.toString(); |
| } |
| |
| /* |
| * Return a string representation of the specified field. |
| */ |
| private static String fullyQualifiedFieldName(Object object, String fieldName) { |
| return fullyQualifiedFieldName(object.getClass(), fieldName); |
| } |
| |
| /* |
| * Return a string representation of the specified method. |
| */ |
| private static String fullyQualifiedMethodSignature(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) { |
| StringBuilder sb = new StringBuilder(200); |
| sb.append(javaClass.getName()); |
| // this check allows us to use this code for constructors, where the methodName is null |
| if (methodName != null) { |
| sb.append('.'); |
| sb.append(methodName); |
| } |
| sb.append('('); |
| int max = parameterTypes.length - 1; |
| if (max != -1) { |
| // stop one short of the end of the array |
| for (int i = 0; i < max; i++) { |
| sb.append(parameterTypes[i].getName()); |
| sb.append(", "); //$NON-NLS-1$ |
| } |
| sb.append(parameterTypes[max].getName()); |
| } |
| sb.append(')'); |
| return sb.toString(); |
| } |
| |
| /* |
| * Return a string representation of the specified method. |
| */ |
| private static String fullyQualifiedMethodSignature(Object receiver, String methodName, Class<?>[] parameterTypes) { |
| return fullyQualifiedMethodSignature(receiver.getClass(), methodName, parameterTypes); |
| } |
| |
| /** |
| * Get a field value, given the containing object and field name. |
| * Return its result. |
| * Useful for accessing private, package, or protected fields. |
| * Object#getFieldValue(String fieldName) |
| */ |
| public static Object fieldValue(Object object, String fieldName) { |
| try { |
| return attemptToGetFieldValue(object, fieldName); |
| } catch (NoSuchFieldException nsfe) { |
| throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(object, fieldName), nsfe); |
| } |
| } |
| |
| /** |
| * Get a static field value, given the containing class and field name. |
| * Return its result. |
| * Useful for accessing private, package, or protected fields. |
| * Class#getStaticFieldValue(String fieldName) |
| */ |
| public static Object staticFieldValue(Class<?> javaClass, String fieldName) { |
| try { |
| return attemptToGetStaticFieldValue(javaClass, fieldName); |
| } catch (NoSuchFieldException nsfe) { |
| throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Execute a zero-argument method, given the receiver and method name. |
| * Return its result. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName) |
| */ |
| public static Object executeMethod(Object receiver, String methodName) { |
| return executeMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Execute a method, given the receiver, |
| * method name, parameter types, and parameters. |
| * Return its result. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) |
| */ |
| public static Object executeMethod(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) { |
| try { |
| return attemptToExecuteMethod(receiver, methodName, parameterTypes, parameters); |
| } catch (NoSuchMethodException nsme) { |
| throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Execute a one-argument method, given the receiver, |
| * method name, parameter type, and parameter. |
| * Return its result. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?> parameterType, Object parameter) |
| */ |
| public static Object executeMethod(Object receiver, String methodName, Class<?> parameterType, Object parameter) { |
| return executeMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Convenience method. |
| * Execute a zero-argument method, given the receiver and method name. |
| * Return its result. |
| * If the method throws an exception, rethrow that exception. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName) |
| */ |
| public static Object executeMethodWithException(Object receiver, String methodName) |
| throws Throwable |
| { |
| return executeMethodWithException(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Convenience method. |
| * Execute a one-argument method, given the receiver, |
| * method name, parameter type, and parameter. |
| * Return its result. |
| * If the method throws an exception, rethrow that exception. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?> parameterType, Object parameter) |
| */ |
| public static Object executeMethodWithException(Object receiver, String methodName, Class<?> parameterType, Object parameter) |
| throws Throwable |
| { |
| return executeMethodWithException(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Execute a method, given the receiver, |
| * method name, parameter types, and parameters. |
| * Return its result. |
| * If the method throws an exception, rethrow that exception. |
| * Useful for invoking private, package, or protected methods. |
| * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) |
| */ |
| public static Object executeMethodWithException(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) |
| throws Throwable |
| { |
| try { |
| return attemptToExecuteMethodWithException(receiver, methodName, parameterTypes, parameters); |
| } catch (NoSuchMethodException nsme) { |
| throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme); |
| } |
| } |
| |
| /** |
| * Execute the specified method with the specified parameters. |
| * Return its result. |
| * Convert exceptions to RuntimeExceptions. |
| */ |
| public static Object executeMethod(Method method, Object receiver, Object[] parameters) { |
| try { |
| return method.invoke(receiver, parameters); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + method, iae); |
| } catch (InvocationTargetException ite) { |
| throw new RuntimeException(method + CR + ite.getTargetException(), ite); |
| } |
| } |
| |
| /** |
| * Execute the specified method with the specified parameters. |
| * Return its result. |
| * If the method throws an exception, rethrow that exception. |
| * Convert all other exceptions to RuntimeExceptions. |
| */ |
| public static Object executeMethodWithException(Method method, Object receiver, Object[] parameters) |
| throws Throwable |
| { |
| try { |
| return method.invoke(receiver, parameters); |
| } catch (IllegalAccessException iae) { |
| throw new RuntimeException(iae + CR + method, iae); |
| } catch (InvocationTargetException ite) { |
| Throwable cause = ite.getCause(); |
| if (cause == null) { |
| throw new RuntimeException(method.toString(), ite); |
| } |
| throw cause; |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Execute a zero-argument static method, |
| * given the class and method name. |
| * Return its result. |
| * Useful for invoking private, package, or protected methods. |
| * Class#executeStaticMethod(String methodName) |
| */ |
| public static Object executeStaticMethod(Class<?> javaClass, String methodName) { |
| return executeStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Execute a static method, given the class, |
| * method name, parameter types, and parameters. |
| * Return its result. |
| * Useful for invoking private, package, or protected methods. |
| * Class#executeStaticMethod(String methodName, Class<?>[] parameterTypes, Object[] parameters) |
| */ |
| public static Object executeStaticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes, Object[] parameters) { |
| try { |
| return attemptToExecuteStaticMethod(javaClass, methodName, parameterTypes, parameters); |
| } catch (NoSuchMethodException nsme) { |
| throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes), nsme); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Execute a static method, given the class, |
| * method name, parameter type, and parameter. |
| * Return its result. |
| * Useful for invoking private, package, or protected methods. |
| * Class#executeStaticMethod(String methodName, Class<?> parameterType, Object parameter) |
| */ |
| public static Object executeStaticMethod(Class<?> javaClass, String methodName, Class<?> parameterType, Object parameter) { |
| return executeStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Execute the specified static method with the specified parameters. |
| * Return its result. |
| * Convert exceptions to RuntimeExceptions. |
| */ |
| public static Object executeStaticMethod(Method method, Object[] parameters) { |
| return executeMethod(method, null, parameters); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a zero-argument method for the specified class |
| * and method name. If the class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method method(Class<?> javaClass, String methodName) throws NoSuchMethodException { |
| return method(javaClass, methodName, ZERO_PARAMETER_TYPES); |
| } |
| |
| /** |
| * Return a method for the specified class, method name, |
| * and formal parameter types. If the class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method method(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException { |
| Method method = null; |
| try { |
| method = javaClass.getDeclaredMethod(methodName, parameterTypes); |
| } catch (NoSuchMethodException ex) { |
| Class<?> superclass = javaClass.getSuperclass(); |
| if (superclass == null) { |
| throw ex; |
| } |
| // recurse |
| return method(superclass, methodName, parameterTypes); |
| } |
| method.setAccessible(true); |
| return method; |
| } |
| |
| /** |
| * Convenience method. |
| * Return a method for the specified class, method name, |
| * and formal parameter type. If the class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method method(Class<?> javaClass, String methodName, Class<?> parameterType) throws NoSuchMethodException { |
| return method(javaClass, methodName, new Class[] {parameterType}); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a zero-argument method for the specified object |
| * and method name. If the object's class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method method(Object object, String methodName) throws NoSuchMethodException { |
| return method(object.getClass(), methodName); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a method for the specified object, method name, |
| * and formal parameter types. If the object's class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method method(Object object, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException { |
| return method(object.getClass(), methodName, parameterTypes); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a method for the specified object, method name, |
| * and formal parameter type. If the object's class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method method(Object object, String methodName, Class<?> parameterType) throws NoSuchMethodException { |
| return method(object.getClass(), methodName, parameterType); |
| } |
| |
| /** |
| * Convenience method. |
| * Return the specified class (without the checked exception). |
| */ |
| public static Class<?> classForName(String className) { |
| try { |
| return Class.forName(className); |
| } catch (ClassNotFoundException ex) { |
| throw new RuntimeException(className, ex); |
| } |
| } |
| |
| /** |
| * Convenience method. |
| * Return a new instance of the specified class, |
| * using the class's default (zero-argument) constructor. |
| * Class#newInstance() |
| */ |
| public static <T> T newInstance(Class<T> javaClass) { |
| return newInstance(javaClass, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a new instance of the specified class, |
| * using the class's default (zero-argument) constructor. |
| * Class#newInstance() |
| */ |
| public static Object newInstance(String className) throws ClassNotFoundException { |
| return newInstance(className, null); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a new instance of the specified class, |
| * using the class's default (zero-argument) constructor. |
| * Class#newInstance() |
| */ |
| public static Object newInstance(String className, ClassLoader classLoader) throws ClassNotFoundException { |
| return newInstance(Class.forName(className, true, classLoader)); |
| } |
| |
| /** |
| * Return a new instance of the specified class, |
| * given the constructor parameter types and parameters. |
| * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) |
| */ |
| public static <T> T newInstance(Class<T> javaClass, Class<?>[] parameterTypes, Object[] parameters) { |
| try { |
| return attemptNewInstance(javaClass, parameterTypes, parameters); |
| } catch (NoSuchMethodException nsme) { |
| throw new RuntimeException(nsme + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), nsme); |
| } |
| } |
| |
| /** |
| * Return a new instance of the specified class, |
| * given the constructor parameter types and parameters. |
| * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) |
| */ |
| public static Object newInstance(String className, Class<?>[] parameterTypes, Object[] parameters) throws ClassNotFoundException { |
| return newInstance(className, parameterTypes, parameters, null); |
| } |
| |
| /** |
| * Return a new instance of the specified class, |
| * given the constructor parameter types and parameters. |
| * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) |
| */ |
| public static Object newInstance(String className, Class<?>[] parameterTypes, Object[] parameters, ClassLoader classLoader) throws ClassNotFoundException { |
| return newInstance(Class.forName(className, true, classLoader), parameterTypes, parameters); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a new instance of the specified class, |
| * given the constructor parameter type and parameter. |
| * Class#newInstance(Class<?> parameterType, Object parameter) |
| */ |
| public static <T> T newInstance(Class<T> javaClass, Class<?> parameterType, Object parameter) { |
| return newInstance(javaClass, new Class[] {parameterType}, new Object[] {parameter}); |
| } |
| |
| /** |
| * Return a new instance of the specified class, |
| * given the constructor parameter type and parameter. |
| * Class#newInstance(Class<?> parameterType, Object parameter) |
| */ |
| public static Object newInstance(String className, Class<?> parameterType, Object parameter) throws ClassNotFoundException { |
| return newInstance(className, parameterType, parameter, null); |
| } |
| |
| /** |
| * Return a new instance of the specified class, |
| * given the constructor parameter type and parameter. |
| * Class#newInstance(Class<?> parameterType, Object parameter) |
| */ |
| public static Object newInstance(String className, Class<?> parameterType, Object parameter, ClassLoader classLoader) throws ClassNotFoundException { |
| return newInstance(Class.forName(className, false, classLoader), parameterType, parameter); |
| } |
| |
| /* |
| * Push the declared fields for the specified class |
| * onto the top of the stack. |
| */ |
| private static void pushDeclaredFields(Class<?> javaClass, Stack<Field> stack) { |
| Field[] fields = declaredFields(javaClass); |
| for (int i = fields.length; i-- > 0; ) { |
| stack.push(fields[i]); |
| } |
| } |
| |
| /* |
| * Push the declared methods for the specified class |
| * onto the top of the stack. |
| */ |
| private static void pushDeclaredMethods(Class<?> javaClass, Stack<Method> stack) { |
| Method[] methods = declaredMethods(javaClass); |
| for (int i = methods.length; i-- > 0; ) { |
| stack.push(methods[i]); |
| } |
| } |
| |
| /** |
| * Set a field value, given the containing object, field name, and new field value. |
| * Useful for accessing private, package, or protected fields. |
| * Object#setFieldValue(String fieldName, Object fieldValue) |
| */ |
| public static void setFieldValue(Object object, String fieldName, Object fieldValue) { |
| try { |
| attemptToSetFieldValue(object, fieldName, fieldValue); |
| } catch (NoSuchFieldException nsfe) { |
| throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(object, fieldName), nsfe); |
| } |
| } |
| |
| /** |
| * Set a static field value, given the containing class, field name, and new field value. |
| * Useful for accessing private, package, or protected fields. |
| * Class#setStaticFieldValue(String fieldName, Object fieldValue) |
| */ |
| public static void setStaticFieldValue(Class<?> javaClass, String fieldName, Object fieldValue) { |
| try { |
| attemptToSetStaticFieldValue(javaClass, fieldName, fieldValue); |
| } catch (NoSuchFieldException nsfe) { |
| throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe); |
| } |
| } |
| |
| /** |
| * Return the short name of the object's class. |
| * Class#getShortName() |
| */ |
| public static String shortClassNameForObject(Object object) { |
| return shortNameFor(object.getClass()); |
| } |
| |
| /** |
| * Return the short name of the class (e.g. "Object"). |
| * Class#getShortName() |
| */ |
| public static String shortNameForClassNamed(String className) { |
| return className.substring(className.lastIndexOf('.') + 1); |
| } |
| |
| /** |
| * Return the short name of the class (e.g. "Object"). |
| * Class#getShortName() |
| */ |
| public static String shortNameFor(Class<?> javaClass) { |
| return shortNameForClassNamed(javaClass.getName()); |
| } |
| |
| /** |
| * Return the nested name of the object's class. |
| * Class#getNestedName() |
| */ |
| public static String nestedClassNameForObject(Object object) { |
| return nestedNameFor(object.getClass()); |
| } |
| |
| /** |
| * Return the nested name of the class (e.g. "Entry"). |
| * Class#getNestedName() |
| */ |
| public static String nestedNameForClassNamed(String className) { |
| return className.substring(className.lastIndexOf(NESTED_CLASS_NAME_SEPARATOR) + 1); |
| } |
| |
| /** |
| * Return the nested name of the class (e.g. "Entry"). |
| * Class#getNestedName() |
| */ |
| public static String nestedNameFor(Class<?> javaClass) { |
| return nestedNameForClassNamed(javaClass.getName()); |
| } |
| |
| /** |
| * Return the "toString()" name of the object's class. |
| */ |
| public static String toStringClassNameForObject(Object object) { |
| return toStringNameFor(object.getClass()); |
| } |
| |
| /** |
| * Return the "toString()" name of the class. |
| * "Member" classes will return only the final name: |
| * "com.foo.bar.TopLevelClass$MemberClass$NestedMemberClass" |
| * => "NestedMemberClass" |
| * "Local" and "anonymous" classes will still return the embedded '$'s: |
| * "com.foo.bar.TopLevelClass$1LocalClass" |
| * => "TopLevelClass$1LocalClass" |
| * "com.foo.bar.TopLevelClass$1" |
| * => "TopLevelClass$1" |
| */ |
| public static String toStringNameForClassNamed(String className) { |
| return classNamedIsMember(className) ? |
| className.substring(className.lastIndexOf(NESTED_CLASS_NAME_SEPARATOR) + 1) |
| : |
| className.substring(className.lastIndexOf('.') + 1); |
| } |
| |
| /** |
| * Return the "toString()" name of the class. |
| */ |
| public static String toStringNameFor(Class<?> javaClass) { |
| return toStringNameForClassNamed(javaClass.getName()); |
| } |
| |
| /** |
| * Return the package name of the class (e.g. "java.lang"). |
| * Class#getPackageName() |
| */ |
| public static String packageNameFor(Class<?> javaClass) { |
| return packageNameForClassNamed(javaClass.getName()); |
| } |
| |
| /** |
| * Return the package name of the class (e.g. "java.lang"). |
| * Class#getPackageName() |
| */ |
| public static String packageNameForClassNamed(String className) { |
| int lastPeriod = className.lastIndexOf('.'); |
| if (lastPeriod == -1) { |
| return ""; //$NON-NLS-1$ |
| } |
| return className.substring(0, lastPeriod); |
| } |
| |
| /** |
| * Return the short name of the class, |
| * followed by its package name (e.g. "Object (java.lang)"). |
| * Class#getShortNameWithPackage() |
| */ |
| public static String shortNameWithPackage(Class<?> javaClass) { |
| StringBuilder sb = new StringBuilder(200); |
| sb.append(shortNameFor(javaClass)); |
| if ( ! javaClass.isPrimitive()) { |
| sb.append(" ("); //$NON-NLS-1$ |
| sb.append(packageNameFor(javaClass)); |
| sb.append(')'); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a zero-argument, static method for the specified class |
| * and method name. If the class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method staticMethod(Class<?> javaClass, String methodName) throws NoSuchMethodException { |
| return staticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES); |
| } |
| |
| /** |
| * Return a static method for the specified class, method name, |
| * and formal parameter types. If the class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method staticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException { |
| Method method = method(javaClass, methodName, parameterTypes); |
| if (Modifier.isStatic(method.getModifiers())) { |
| return method; |
| } |
| throw new NoSuchMethodException(fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes)); |
| } |
| |
| /** |
| * Convenience method. |
| * Return a static method for the specified class, method name, |
| * and formal parameter type. If the class does not directly |
| * implement the method, look for it in the class's superclasses. |
| * Set accessible to true, so we can access |
| * private/package/protected methods. |
| */ |
| public static Method staticMethod(Class<?> javaClass, String methodName, Class<?> parameterTypes) throws NoSuchMethodException { |
| return staticMethod(javaClass, methodName, new Class[] {parameterTypes}); |
| } |
| |
| /** |
| * Return whether the specified class can be "declared" in code; |
| * i.e. it is either a "top-level" class or a "member" class, but it |
| * is not an "array" class. This method rolls together all the checks |
| * from the other methods for a bit of a performance tweak. |
| * Class#isDeclarable() |
| */ |
| public static boolean classNamedIsDeclarable(String className) { |
| if (className.charAt(0) == ARRAY_INDICATOR) { |
| return false; // it is an "array" class |
| } |
| int index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); |
| if (index == -1) { |
| return true; // it is a "top-level" class |
| } |
| do { |
| // the character immediately after each dollar sign cannot be a digit |
| index++; |
| if (Character.isDigit(className.charAt(index))) { |
| return false; |
| } |
| index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR, index); |
| } while (index != -1); |
| return true; |
| } |
| |
| /** |
| * Return whether the specified class is a "top-level" class, |
| * as opposed to a "member", "local", or "anonymous" class, |
| * using the standard jdk naming conventions (i.e. the class |
| * name does NOT contain a '$': "TopLevelClass"). |
| * Class#isTopLevel() |
| */ |
| public static boolean classNamedIsTopLevel(String className) { |
| if (classNamedIsArray(className)) { |
| return false; |
| } |
| return className.indexOf(NESTED_CLASS_NAME_SEPARATOR) == -1; |
| } |
| |
| /** |
| * Return whether the specified class is a "member" class, |
| * as opposed to a "top-level", "local", or "anonymous" class, |
| * using the standard jdk naming conventions (i.e. the class |
| * name contains at least one '$' and all the names between |
| * each '$' are legal class names: |
| * "TopLevelClass$MemberClass$NestedMemberClass"). |
| * Class#isMember() |
| */ |
| public static boolean classNamedIsMember(String className) { |
| if (classNamedIsArray(className)) { |
| return false; |
| } |
| int index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); |
| if (index == -1) { |
| return false; // it is a "top-level" class |
| } |
| do { |
| // the character immediately after each dollar sign cannot be a digit |
| index++; |
| if (Character.isDigit(className.charAt(index))) { |
| return false; |
| } |
| index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR, index); |
| } while (index != -1); |
| return true; |
| } |
| |
| /** |
| * Return whether the specified class is a "local" class, |
| * as opposed to a "top-level", "member", or "anonymous" class, |
| * using the standard jdk (or Eclipse) naming conventions. |
| * In the jdk, the class name ends with '$nnnXXX' where the '$' is |
| * followed by a series of numeric digits which are followed by the |
| * local class name: "TopLevelClass$1LocalClass". |
| * In Eclipse, the class name ends with '$nnn$XXX' where the '$' is |
| * followed by a series of numeric digits which are separated from |
| * the local class name by another '$': "TopLevelClass$1$LocalClass". |
| * Class#isLocal() |
| */ |
| public static boolean classNamedIsLocal(String className) { |
| if (classNamedIsArray(className)) { |
| return false; |
| } |
| int dollar = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); |
| if (dollar == -1) { |
| return false; |
| } |
| if ( ! Character.isDigit(className.charAt(dollar + 1))) { |
| return false; |
| } |
| int len = className.length(); |
| for (int i = dollar + 2; i < len; i++) { |
| if (Character.isJavaIdentifierStart(className.charAt(i))) { |
| return true; |
| } |
| } |
| // all the characters past the $ are digits (anonymous) |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is an "anonymous" class, |
| * as opposed to a "top-level", "member", or "local" class, |
| * using the standard jdk naming conventions (i.e. the class |
| * name ends with '$nnn' where all the characters past the |
| * last '$' are numeric digits: "TopLevelClass$1"). |
| * Class#isAnonymous() |
| */ |
| public static boolean classNamedIsAnonymous(String className) { |
| if (classNamedIsArray(className)) { |
| return false; |
| } |
| int dollar = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); |
| if (dollar == -1) { |
| return false; |
| } |
| int start = dollar + 1; |
| for (int i = className.length(); i-- > start; ) { |
| if ( ! Character.isDigit(className.charAt(i))) { |
| return false; |
| } |
| } |
| // all the characters past the $ are digits |
| return true; |
| } |
| |
| /** |
| * Return the "array depth" of the specified class. |
| * The depth is the number of dimensions for an array type. |
| * Non-array types have a depth of zero. |
| * Class#getArrayDepth() |
| */ |
| public static int arrayDepthFor(Class<?> javaClass) { |
| int depth = 0; |
| while (javaClass.isArray()) { |
| depth++; |
| javaClass = javaClass.getComponentType(); |
| } |
| return depth; |
| } |
| |
| /** |
| * Return the "array depth" of the specified object. |
| * The depth is the number of dimensions for an array. |
| * Non-arrays have a depth of zero. |
| */ |
| public static int arrayDepthForObject(Object object) { |
| return arrayDepthFor(object.getClass()); |
| } |
| |
| /** |
| * Return the "array depth" of the specified class. |
| * The depth is the number of dimensions for an array type. |
| * Non-array types have a depth of zero. |
| * @see java.lang.Class#getName() |
| * Class#getArrayDepth() |
| */ |
| public static int arrayDepthForClassNamed(String className) { |
| int depth = 0; |
| while (className.charAt(depth) == ARRAY_INDICATOR) { |
| depth++; |
| } |
| return depth; |
| } |
| |
| /** |
| * Return whether the specified class is an array type. |
| * @see java.lang.Class#getName() |
| */ |
| public static boolean classNamedIsArray(String className) { |
| return className.charAt(0) == ARRAY_INDICATOR; |
| } |
| |
| /** |
| * Return the "element type" of the specified class. |
| * The element type is the base type held by an array type. |
| * A non-array type simply returns itself. |
| * Class#getElementType() |
| */ |
| public static Class<?> elementTypeFor(Class<?> javaClass) { |
| while (javaClass.isArray()) { |
| javaClass = javaClass.getComponentType(); |
| } |
| return javaClass; |
| } |
| |
| /** |
| * Return the "element type" of the specified object. |
| * The element type is the base type held by an array. |
| * A non-array simply returns its class. |
| */ |
| public static Class<?> elementTypeForObject(Object object) { |
| return elementTypeFor(object.getClass()); |
| } |
| |
| /** |
| * Return the "element type" of the specified class. |
| * The element type is the base type held by an array type. |
| * Non-array types simply return themselves. |
| * Class#getElementType() |
| */ |
| public static String elementTypeNameFor(Class<?> javaClass) { |
| return elementTypeFor(javaClass).getName(); |
| } |
| |
| /** |
| * Return the "element type" of the specified class. |
| * The element type is the base type held by an array type. |
| * Non-array types simply return themselves. |
| * @see java.lang.Class#getName() |
| * Class#getElementType() |
| */ |
| public static String elementTypeNameForClassNamed(String className) { |
| int depth = arrayDepthForClassNamed(className); |
| if (depth == 0) { |
| // the name is in the form: "java.lang.Object" or "int" |
| return className; |
| } |
| int last = className.length() - 1; |
| if (className.charAt(depth) == REFERENCE_CLASS_CODE) { |
| // the name is in the form: "[[[Ljava.lang.Object;" |
| return className.substring(depth + 1, last); // drop the trailing ';' |
| } |
| // the name is in the form: "[[[I" |
| return classNameForCode(className.charAt(last)); |
| } |
| |
| /** |
| * Return whether the specified class is a "reference" |
| * class (i.e. neither 'void' nor one of the primitive variable classes, |
| * ['boolean', 'int', 'float', etc.]). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classNamedIsReference(String className) { |
| return ! classNamedIsPrimitive(className); |
| } |
| |
| /** |
| * Return whether the specified class is a primitive |
| * class (i.e. 'void' or one of the primitive variable classes, |
| * ['boolean', 'int', 'float', etc.]). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classNamedIsPrimitive(String className) { |
| if (classNamedIsArray(className) || (className.length() > maxPrimitiveClassNameLength())) { |
| return false; // performance tweak |
| } |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].javaClass.getName().equals(className)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is a "variable" primitive |
| * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classNamedIsVariablePrimitive(String className) { |
| return classNamedIsPrimitive(className) |
| && ( ! className.equals(VOID_CLASS_NAME)); |
| } |
| |
| /** |
| * Return whether the specified class is a primitive wrapper |
| * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes, |
| * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classNamedIsPrimitiveWrapperClass(String className) { |
| if (classNamedIsArray(className) || (className.length() > maxPrimitiveWrapperClassNameLength())) { |
| return false; // performance tweak |
| } |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].wrapperClass.getName().equals(className)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is a "variable" primitive |
| * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classNamedIsVariablePrimitiveWrapperClass(String className) { |
| return classNamedIsPrimitiveWrapperClass(className) |
| && ( ! className.equals(VOID_WRAPPER_CLASS_NAME)); |
| } |
| |
| /** |
| * Return whether the specified class is a primitive wrapper |
| * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes, |
| * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classIsPrimitiveWrapperClass(Class<?> javaClass) { |
| if (javaClass.isArray() || (javaClass.getName().length() > maxPrimitiveWrapperClassNameLength())) { |
| return false; // performance tweak |
| } |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].wrapperClass == javaClass) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is a "variable" primitive |
| * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). |
| * NB: void.class.isPrimitive() == true |
| */ |
| public static boolean classIsVariablePrimitiveWrapperClass(Class<?> javaClass) { |
| return classIsPrimitiveWrapperClass(javaClass) |
| && (javaClass != java.lang.Void.class); |
| } |
| |
| /** |
| * Return the class name for the specified class code. |
| * @see java.lang.Class#getName() |
| */ |
| public static String classNameForCode(char classCode) { |
| return classForCode(classCode).getName(); |
| } |
| |
| /** |
| * Return the class name for the specified class code. |
| * @see java.lang.Class#getName() |
| */ |
| public static String classNameForCode(int classCode) { |
| return classNameForCode((char) classCode); |
| } |
| |
| /** |
| * Return the class for the specified class code. |
| * @see java.lang.Class#getName() |
| */ |
| public static Class<?> classForCode(char classCode) { |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].code == classCode) { |
| return codes[i].javaClass; |
| } |
| } |
| throw new IllegalArgumentException(String.valueOf(classCode)); |
| } |
| |
| /** |
| * Return the class for the specified class code. |
| * @see java.lang.Class#getName() |
| */ |
| public static Class<?> classForCode(int classCode) { |
| return classForCode((char) classCode); |
| } |
| |
| /** |
| * Return the class code for the specified class. |
| * @see java.lang.Class#getName() |
| */ |
| public static char codeForClass(Class<?> javaClass) { |
| if (( ! javaClass.isArray()) && (javaClass.getName().length() <= maxPrimitiveClassNameLength())) { |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].javaClass == javaClass) { |
| return codes[i].code; |
| } |
| } |
| } |
| throw new IllegalArgumentException(javaClass.getName()); |
| } |
| |
| /** |
| * Return the class code for the specified class. |
| * @see java.lang.Class#getName() |
| */ |
| public static char codeForClassNamed(String className) { |
| if (( ! classNamedIsArray(className)) && (className.length() <= maxPrimitiveClassNameLength())) { |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].javaClass.getName().equals(className)) { |
| return codes[i].code; |
| } |
| } |
| } |
| throw new IllegalArgumentException(className); |
| } |
| |
| /** |
| * Return the class for the specified "type declaration". |
| */ |
| public static Class<?> classForTypeDeclaration(String typeDeclaration) throws ClassNotFoundException { |
| return classForTypeDeclaration(typeDeclaration, null); |
| } |
| |
| /** |
| * Return the class for the specified "type declaration", |
| * using the specified class loader. |
| */ |
| public static Class<?> classForTypeDeclaration(String typeDeclaration, ClassLoader classLoader) throws ClassNotFoundException { |
| TypeDeclaration td = typeDeclaration(typeDeclaration); |
| return classForTypeDeclaration(td.elementTypeName, td.arrayDepth, classLoader); |
| } |
| |
| private static TypeDeclaration typeDeclaration(String typeDeclaration) { |
| typeDeclaration = StringTools.removeAllWhitespace(typeDeclaration); |
| int arrayDepth = arrayDepthForTypeDeclaration_(typeDeclaration); |
| String elementTypeName = typeDeclaration.substring(0, typeDeclaration.length() - (arrayDepth * 2)); |
| return new TypeDeclaration(elementTypeName, arrayDepth); |
| } |
| |
| /** |
| * Return the class for the specified "type declaration". |
| */ |
| public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth) throws ClassNotFoundException { |
| return classForTypeDeclaration(elementTypeName, arrayDepth, null); |
| } |
| |
| /** |
| * Return the class for the specified "type declaration", |
| * using the specified class loader. |
| */ |
| // see the "Evaluation" of jdk bug 6446627 for a discussion of loading classes |
| public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth, ClassLoader classLoader) throws ClassNotFoundException { |
| // primitives cannot be loaded via Class#forName(), |
| // so check for a primitive class name first |
| Primitive pcc = null; |
| if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].javaClass.getName().equals(elementTypeName)) { |
| pcc = codes[i]; |
| break; |
| } |
| } |
| } |
| |
| // non-array |
| if (arrayDepth == 0) { |
| return (pcc == null) ? Class.forName(elementTypeName, false, classLoader) : pcc.javaClass; |
| } |
| |
| // array |
| StringBuilder sb = new StringBuilder(100); |
| for (int i = arrayDepth; i-- > 0; ) { |
| sb.append(ARRAY_INDICATOR); |
| } |
| if (pcc == null) { |
| sb.append(REFERENCE_CLASS_CODE); |
| sb.append(elementTypeName); |
| sb.append(REFERENCE_CLASS_NAME_DELIMITER); |
| } else { |
| sb.append(pcc.code); |
| } |
| return Class.forName(sb.toString(), false, classLoader); |
| } |
| |
| /** |
| * Return the class name for the specified "type declaration"; e.g. |
| * "int[]" -> "[I" |
| * @see java.lang.Class#getName() |
| */ |
| public static String classNameForTypeDeclaration(String typeDeclaration) { |
| TypeDeclaration td = typeDeclaration(typeDeclaration); |
| return classNameForTypeDeclaration(td.elementTypeName, td.arrayDepth); |
| } |
| |
| /** |
| * Return the array depth for the specified "type declaration"; e.g. |
| * "int[]" -> 1 |
| */ |
| public static int arrayDepthForTypeDeclaration(String typeDeclaration) { |
| return arrayDepthForTypeDeclaration_(StringTools.removeAllWhitespace(typeDeclaration)); |
| } |
| |
| /* |
| * Assume no whitespace in the type declaration. |
| */ |
| private static int arrayDepthForTypeDeclaration_(String typeDeclaration) { |
| int last = typeDeclaration.length() - 1; |
| int depth = 0; |
| int close = last; |
| while (typeDeclaration.charAt(close) == TYPE_DECLARATION_ARRAY_CLOSE) { |
| if (typeDeclaration.charAt(close - 1) == TYPE_DECLARATION_ARRAY_OPEN) { |
| depth++; |
| } else { |
| throw new IllegalArgumentException("invalid type declaration: " + typeDeclaration); //$NON-NLS-1$ |
| } |
| close = last - (depth * 2); |
| } |
| return depth; |
| } |
| |
| /** |
| * Return the class name for the specified "type declaration". |
| * @see java.lang.Class#getName() |
| */ |
| public static String classNameForTypeDeclaration(String elementTypeName, int arrayDepth) { |
| // non-array |
| if (arrayDepth == 0) { |
| return elementTypeName; |
| } |
| |
| if (elementTypeName.equals(VOID_CLASS_NAME)) { |
| throw new IllegalArgumentException('\'' + VOID_CLASS_NAME + "' must have an array depth of zero: " + arrayDepth + '.'); //$NON-NLS-1$ |
| } |
| // array |
| StringBuilder sb = new StringBuilder(100); |
| for (int i = arrayDepth; i-- > 0; ) { |
| sb.append(ARRAY_INDICATOR); |
| } |
| |
| // look for a primitive first |
| Primitive pcc = null; |
| if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| if (codes[i].javaClass.getName().equals(elementTypeName)) { |
| pcc = codes[i]; |
| break; |
| } |
| } |
| } |
| |
| if (pcc == null) { |
| sb.append(REFERENCE_CLASS_CODE); |
| sb.append(elementTypeName); |
| sb.append(REFERENCE_CLASS_NAME_DELIMITER); |
| } else { |
| sb.append(pcc.code); |
| } |
| |
| return sb.toString(); |
| } |
| |
| private static int maxPrimitiveClassNameLength() { |
| if (MAX_PRIMITIVE_CLASS_NAME_LENGTH == -1) { |
| MAX_PRIMITIVE_CLASS_NAME_LENGTH = calculateMaxPrimitiveClassNameLength(); |
| } |
| return MAX_PRIMITIVE_CLASS_NAME_LENGTH; |
| } |
| |
| private static int calculateMaxPrimitiveClassNameLength() { |
| int max = -1; |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| int len = codes[i].javaClass.getName().length(); |
| if (len > max) { |
| max = len; |
| } |
| } |
| return max; |
| } |
| |
| private static int maxPrimitiveWrapperClassNameLength() { |
| if (MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH == -1) { |
| MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = calculateMaxPrimitiveWrapperClassNameLength(); |
| } |
| return MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH; |
| } |
| |
| private static int calculateMaxPrimitiveWrapperClassNameLength() { |
| int max = -1; |
| Primitive[] codes = primitives(); |
| for (int i = codes.length; i-- > 0; ) { |
| int len = codes[i].wrapperClass.getName().length(); |
| if (len > max) { |
| max = len; |
| } |
| } |
| return max; |
| } |
| |
| private static Primitive[] primitives() { |
| if (PRIMITIVES == null) { |
| PRIMITIVES = buildPrimitives(); |
| } |
| return PRIMITIVES; |
| } |
| |
| /** |
| * NB: void.class.isPrimitive() == true |
| */ |
| private static Primitive[] buildPrimitives() { |
| Primitive[] result = new Primitive[9]; |
| result[0] = new Primitive(BYTE_CODE, java.lang.Byte.class); |
| result[1] = new Primitive(CHAR_CODE, java.lang.Character.class); |
| result[2] = new Primitive(DOUBLE_CODE, java.lang.Double.class); |
| result[3] = new Primitive(FLOAT_CODE, java.lang.Float.class); |
| result[4] = new Primitive(INT_CODE, java.lang.Integer.class); |
| result[5] = new Primitive(LONG_CODE, java.lang.Long.class); |
| result[6] = new Primitive(SHORT_CODE, java.lang.Short.class); |
| result[7] = new Primitive(BOOLEAN_CODE, java.lang.Boolean.class); |
| result[8] = new Primitive(VOID_CODE, java.lang.Void.class); |
| return result; |
| } |
| |
| /** |
| * Suppress default constructor, ensuring non-instantiability. |
| */ |
| private ClassTools() { |
| super(); |
| throw new UnsupportedOperationException(); |
| } |
| |
| |
| // ********** member classes ********** |
| |
| private static class Primitive { |
| final char code; |
| final Class<?> javaClass; |
| final Class<?> wrapperClass; |
| private static final String WRAPPER_CLASS_TYPE_FIELD_NAME = "TYPE"; //$NON-NLS-1$ |
| // e.g. java.lang.Boolean.TYPE => boolean.class |
| Primitive(char code, Class<?> wrapperClass) { |
| this.code = code; |
| this.wrapperClass = wrapperClass; |
| this.javaClass = (Class<?>) staticFieldValue(wrapperClass, WRAPPER_CLASS_TYPE_FIELD_NAME); |
| } |
| } |
| |
| private static class TypeDeclaration { |
| final String elementTypeName; |
| final int arrayDepth; |
| TypeDeclaration(String elementTypeName, int arrayDepth) { |
| this.elementTypeName = elementTypeName; |
| this.arrayDepth = arrayDepth; |
| } |
| } |
| |
| } |