/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.utility; 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; import org.eclipse.persistence.tools.workbench.utility.string.StringTools; /** * 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 REFERENCE_CLASS_CODE = 'L'; public static final char REFERENCE_CLASS_NAME_DELIMITER = ';'; private static PrimitiveClassCode[] primitiveClassCodes; 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'; /** * Return all the fields for the * specified class, including inherited fields. * Class#allFields() */ public static Field[] allFields(Class javaClass) { Stack stack = new Stack(); for (Class tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) { pushDeclaredFields(tempClass, stack); } Collections.reverse(stack); return (Field[]) 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 stack = new Stack(); for (Class tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) { pushDeclaredMethods(tempClass, stack); } Collections.reverse(stack); return (Method[]) 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 Object attemptNewInstance(Class 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 Object attemptNewInstance(Class 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 Object attemptNewInstance(Class 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 invoke 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#invoke(String methodName) throws NoSuchMethodException */ public static Object attemptToInvokeMethod(Object receiver, String methodName) throws NoSuchMethodException { return attemptToInvokeMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); } /** * Convenience method. * Attempt to invoke 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#invoke(String methodName, Class parameterType, Object parameter) throws NoSuchMethodException */ public static Object attemptToInvokeMethod(Object receiver, String methodName, Class parameterType, Object parameter) throws NoSuchMethodException { return attemptToInvokeMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); } /** * Attempt to invoke 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#invoke(String methodName, Class[] parameterTypes, Object[] parameters) throws NoSuchMethodException */ public static Object attemptToInvokeMethod(Object receiver, String methodName, Class[] parameterTypes, Object[] parameters) throws NoSuchMethodException { return invokeMethod(method(receiver, methodName, parameterTypes), receiver, parameters); } /** * Attempt to invoke 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 invoked method throws an exception, rethrow that exception. * Useful for invoking private, package, or protected methods. * Object#invoke(String methodName, Class[] parameterTypes, Object[] parameters) throws NoSuchMethodException */ public static Object attemptToInvokeMethodWithException(Object receiver, String methodName, Class[] parameterTypes, Object[] parameters) throws Throwable, NoSuchMethodException { return invokeMethodWithException(method(receiver, methodName, parameterTypes), receiver, parameters); } /** * Convenience method. * Attempt to invoke 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#invokeStaticMethod(String methodName) throws NoSuchMethodException */ public static Object attemptToInvokeStaticMethod(Class javaClass, String methodName) throws NoSuchMethodException { return attemptToInvokeStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); } /** * Attempt to invoke 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#invokeStaticMethod(String methodName, Class[] parameterTypes, Object[] parameters) throws NoSuchMethodException */ public static Object attemptToInvokeStaticMethod(Class javaClass, String methodName, Class[] parameterTypes, Object[] parameters) throws NoSuchMethodException { return invokeStaticMethod(staticMethod(javaClass, methodName, parameterTypes), parameters); } /** * Convenience method. * Attempt to invoke 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#invokeStaticMethod(String methodName, Class parameterType, Object parameter) throws NoSuchMethodException */ public static Object attemptToInvokeStaticMethod(Class javaClass, String methodName, Class parameterType, Object parameter) throws NoSuchMethodException { return attemptToInvokeStaticMethod(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 Constructor constructor(Class 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 Constructor constructor(Class javaClass, Class[] parameterTypes) throws NoSuchMethodException { Constructor 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 Constructor constructor(Class 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 (int i = 0; i < fields.length; i++) { fields[i].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 (int i = 0; i < methods.length; i++) { methods[i].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 Constructor defaultConstructor(Class 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) { StringBuffer sb = new StringBuffer(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) { StringBuffer sb = new StringBuffer(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('('); for (int i = 0; i < parameterTypes.length; i++) { sb.append(parameterTypes[i].getName()); if (i < parameterTypes.length - 1) sb.append(", "); } 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 getFieldValue(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 getStaticFieldValue(Class javaClass, String fieldName) { try { return attemptToGetStaticFieldValue(javaClass, fieldName); } catch (NoSuchFieldException nsfe) { throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe); } } /** * Convenience method. * Invoke a zero-argument method, given the receiver and method name. * Return its result. * Useful for invoking private, package, or protected methods. * Object#invoke(String methodName) */ public static Object invokeMethod(Object receiver, String methodName) { return invokeMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); } /** * Invoke a method, given the receiver, * method name, parameter types, and parameters. * Return its result. * Useful for invoking private, package, or protected methods. * Object#invoke(String methodName, Class[] parameterTypes, Object[] parameters) */ public static Object invokeMethod(Object receiver, String methodName, Class[] parameterTypes, Object[] parameters) { try { return attemptToInvokeMethod(receiver, methodName, parameterTypes, parameters); } catch (NoSuchMethodException nsme) { throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme); } } /** * Convenience method. * Invoke 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#invoke(String methodName, Class parameterType, Object parameter) */ public static Object invokeMethod(Object receiver, String methodName, Class parameterType, Object parameter) { return invokeMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); } /** * Convenience method. * Invoke 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#invoke(String methodName) */ public static Object invokeMethodWithException(Object receiver, String methodName) throws Throwable { return invokeMethodWithException(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); } /** * Convenience method. * Invoke 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#invoke(String methodName, Class parameterType, Object parameter) */ public static Object invokeMethodWithException(Object receiver, String methodName, Class parameterType, Object parameter) throws Throwable { return invokeMethodWithException(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); } /** * Invoke 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#invoke(String methodName, Class[] parameterTypes, Object[] parameters) */ public static Object invokeMethodWithException(Object receiver, String methodName, Class[] parameterTypes, Object[] parameters) throws Throwable { try { return attemptToInvokeMethodWithException(receiver, methodName, parameterTypes, parameters); } catch (NoSuchMethodException nsme) { throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme); } } /** * Invoke the specified method with the specified parameters. * Return its result. * Convert exceptions to RuntimeExceptions. */ public static Object invokeMethod(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); } } /** * Invoke 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 invokeMethodWithException(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. * Invoke a zero-argument static method, * given the class and method name. * Return its result. * Useful for invoking private, package, or protected methods. * Class#invokeStaticMethod(String methodName) */ public static Object invokeStaticMethod(Class javaClass, String methodName) { return invokeStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); } /** * Invoke a static method, given the class, * method name, parameter types, and parameters. * Return its result. * Useful for invoking private, package, or protected methods. * Class#invokeStaticMethod(String methodName, Class[] parameterTypes, Object[] parameters) */ public static Object invokeStaticMethod(Class javaClass, String methodName, Class[] parameterTypes, Object[] parameters) { try { return attemptToInvokeStaticMethod(javaClass, methodName, parameterTypes, parameters); } catch (NoSuchMethodException nsme) { throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes), nsme); } } /** * Convenience method. * Invoke a static method, given the class, * method name, parameter type, and parameter. * Return its result. * Useful for invoking private, package, or protected methods. * Class#invokeStaticMethod(String methodName, Class parameterType, Object parameter) */ public static Object invokeStaticMethod(Class javaClass, String methodName, Class parameterType, Object parameter) { return invokeStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter}); } /** * Invoke the specified static method with the specified parameters. * Return its result. * Convert exceptions to RuntimeExceptions. */ public static Object invokeStaticMethod(Method method, Object[] parameters) { return invokeMethod(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 (w/o 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 Object newInstance(Class 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 Object newInstance(Class 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 Object newInstance(Class 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 stack) { Field[] fields = declaredFields(javaClass); for (int i = fields.length - 1; i >= 0; i--) { 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 stack) { Method[] methods = declaredMethods(javaClass); for (int i = methods.length - 1; i >= 0; i--) { 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 ""; } 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) { StringBuffer sb = new StringBuffer(200); sb.append(shortNameFor(javaClass)); if ( ! javaClass.isPrimitive()) { sb.append(" ("); 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; } for (int i = dollar + 2; i < className.length(); 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. not void or one of the primitives). */ public static boolean classNamedIsReference(String className) { return ! classNamedIsNonReference(className); } /** * Return whether the specified class is a "non-reference" * class (i.e. void or one of the primitives). */ public static boolean classNamedIsNonReference(String className) { PrimitiveClassCode[] codes = getPrimitiveClassCodes(); for (int i = codes.length; i-- > 0; ) { if (codes[i].javaClass.getName().equals(className)) { return true; } } return false; } /** * 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) { PrimitiveClassCode[] codes = getPrimitiveClassCodes(); 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) { PrimitiveClassCode[] codes = getPrimitiveClassCodes(); 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) { PrimitiveClassCode[] codes = getPrimitiveClassCodes(); 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 specified "type declaration". */ public static Class classForTypeDeclaration(String elementTypeName, int arrayDepth) throws ClassNotFoundException { return classForTypeDeclaration(elementTypeName, arrayDepth, null); } /** * Return the class for 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 PrimitiveClassCode[] codes = getPrimitiveClassCodes(); PrimitiveClassCode pcc = null; 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 StringBuffer sb = new StringBuffer(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 specified "type declaration". */ public static String classNameForTypeDeclaration(String elementTypeName, int arrayDepth) { // non-array if (arrayDepth == 0) { return elementTypeName; } if (elementTypeName.equals(void.class.getName())) { throw new IllegalArgumentException("'void' must have an array depth of zero: " + arrayDepth + '.'); } // array StringBuffer sb = new StringBuffer(100); for (int i = arrayDepth; i-- > 0; ) { sb.append(ARRAY_INDICATOR); } // look for a primitive first PrimitiveClassCode[] codes = getPrimitiveClassCodes(); PrimitiveClassCode pcc = null; 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 PrimitiveClassCode[] getPrimitiveClassCodes() { if (primitiveClassCodes == null) { primitiveClassCodes = buildPrimitiveClassCodes(); } return primitiveClassCodes; } private static PrimitiveClassCode[] buildPrimitiveClassCodes() { PrimitiveClassCode[] result = new PrimitiveClassCode[9]; result[0] = new PrimitiveClassCode(BYTE_CODE, byte.class); result[1] = new PrimitiveClassCode(CHAR_CODE, char.class); result[2] = new PrimitiveClassCode(DOUBLE_CODE, double.class); result[3] = new PrimitiveClassCode(FLOAT_CODE, float.class); result[4] = new PrimitiveClassCode(INT_CODE, int.class); result[5] = new PrimitiveClassCode(LONG_CODE, long.class); result[6] = new PrimitiveClassCode(SHORT_CODE, short.class); result[7] = new PrimitiveClassCode(BOOLEAN_CODE, boolean.class); result[8] = new PrimitiveClassCode(VOID_CODE, void.class); return result; } /** * Suppress default constructor, ensuring non-instantiability. */ private ClassTools() { super(); throw new UnsupportedOperationException(); } // ********** member class ********** private static class PrimitiveClassCode { char code; Class javaClass; PrimitiveClassCode(char code, Class javaClass) { this.code = code; this.javaClass = javaClass; } } }