From 39c9476337d69f34cb1ace57067f0d2a009785a6 Mon Sep 17 00:00:00 2001 From: "James W. Carman" Date: Thu, 17 Nov 2005 16:51:02 +0000 Subject: [PATCH] Refactored getClass() to support spaces in class names. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@345284 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/commons/lang/ClassUtils.java | 706 +++++++++++------- .../apache/commons/lang/ClassUtilsTest.java | 104 +++ 2 files changed, 539 insertions(+), 271 deletions(-) diff --git a/src/java/org/apache/commons/lang/ClassUtils.java b/src/java/org/apache/commons/lang/ClassUtils.java index 1e978ea83..0311d14d7 100644 --- a/src/java/org/apache/commons/lang/ClassUtils.java +++ b/src/java/org/apache/commons/lang/ClassUtils.java @@ -23,223 +23,264 @@ import java.util.Map; /** *

Operates on classes without using reflection.

- * - *

This class handles invalid null inputs as best it can. - * Each method documents its behaviour in more detail.

+ *

+ *

This class handles invalid null inputs as best it can. Each method documents its behaviour in more + * detail.

* * @author Stephen Colebourne * @author Gary Gregory * @author Norm Deane * @author Alban Peignier - * @since 2.0 * @version $Id$ + * @since 2.0 */ -public class ClassUtils { - +public class ClassUtils +{ /** *

The package separator character: '.' == {@value}.

*/ public static final char PACKAGE_SEPARATOR_CHAR = '.'; - /** *

The package separator String: ".".

*/ - public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); - + public static final String PACKAGE_SEPARATOR = String.valueOf( PACKAGE_SEPARATOR_CHAR ); /** *

The inner class separator character: '$' == {@value}.

*/ public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; - /** *

The inner class separator String: "$".

*/ - public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); - - /** - * Maps primitive Classes to their corresponding wrapper Class. - */ - private static Map primitiveWrapperMap = new HashMap(); - static { - primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); - primitiveWrapperMap.put(Byte.TYPE, Byte.class); - primitiveWrapperMap.put(Character.TYPE, Character.class); - primitiveWrapperMap.put(Short.TYPE, Short.class); - primitiveWrapperMap.put(Integer.TYPE, Integer.class); - primitiveWrapperMap.put(Long.TYPE, Long.class); - primitiveWrapperMap.put(Double.TYPE, Double.class); - primitiveWrapperMap.put(Float.TYPE, Float.class); - primitiveWrapperMap.put(Void.TYPE, Void.TYPE); - } - + public static final String INNER_CLASS_SEPARATOR = String.valueOf( INNER_CLASS_SEPARATOR_CHAR ); /** - *

ClassUtils instances should NOT be constructed in standard programming. - * Instead, the class should be used as - * ClassUtils.getShortClassName(cls).

- * - *

This constructor is public to permit tools that require a JavaBean - * instance to operate.

+ * Maps primitive Classes to their corresponding wrapper Class. */ - public ClassUtils() { - super(); + private static Map primitiveWrapperMap = new HashMap(); + + static + { + primitiveWrapperMap.put( Boolean.TYPE, Boolean.class ); + primitiveWrapperMap.put( Byte.TYPE, Byte.class ); + primitiveWrapperMap.put( Character.TYPE, Character.class ); + primitiveWrapperMap.put( Short.TYPE, Short.class ); + primitiveWrapperMap.put( Integer.TYPE, Integer.class ); + primitiveWrapperMap.put( Long.TYPE, Long.class ); + primitiveWrapperMap.put( Double.TYPE, Double.class ); + primitiveWrapperMap.put( Float.TYPE, Float.class ); + primitiveWrapperMap.put( Void.TYPE, Void.TYPE ); + } + + /** + * Maps a primitive class name to its corresponding abbreviation used in array class names. + */ + private static Map abbreviationMap = new HashMap(); + + static + { + abbreviationMap.put( "int", "I" ); + abbreviationMap.put( "boolean", "Z" ); + abbreviationMap.put( "float", "F" ); + abbreviationMap.put( "long", "J" ); + abbreviationMap.put( "short", "S" ); + abbreviationMap.put( "byte", "B" ); + abbreviationMap.put( "double", "D" ); + abbreviationMap.put( "char", "C" ); + } + + /** + *

ClassUtils instances should NOT be constructed in standard programming. Instead, the class should be used as + * ClassUtils.getShortClassName(cls).

+ *

+ *

This constructor is public to permit tools that require a JavaBean instance to operate.

+ */ + public ClassUtils() + { + super(); } // Short class name // ---------------------------------------------------------------------- + /** *

Gets the class name minus the package name for an Object.

- * - * @param object the class to get the short name for, may be null - * @param valueIfNull the value to return if null + * + * @param object the class to get the short name for, may be null + * @param valueIfNull the value to return if null * @return the class name of the object without the package name, or the null value */ - public static String getShortClassName(Object object, String valueIfNull) { - if (object == null) { + public static String getShortClassName( Object object, String valueIfNull ) + { + if( object == null ) + { return valueIfNull; } - return getShortClassName(object.getClass().getName()); + return getShortClassName( object.getClass().getName() ); } - + /** *

Gets the class name minus the package name from a Class.

- * - * @param cls the class to get the short name for. + * + * @param cls the class to get the short name for. * @return the class name without the package name or an empty string */ - public static String getShortClassName(Class cls) { - if (cls == null) { + public static String getShortClassName( Class cls ) + { + if( cls == null ) + { return StringUtils.EMPTY; } - return getShortClassName(cls.getName()); + return getShortClassName( cls.getName() ); } - + /** *

Gets the class name minus the package name from a String.

- * + *

*

The string passed in is assumed to be a class name - it is not checked.

- * - * @param className the className to get the short name for + * + * @param className the className to get the short name for * @return the class name of the class without the package name or an empty string */ - public static String getShortClassName(String className) { - if (className == null) { + public static String getShortClassName( String className ) + { + if( className == null ) + { return StringUtils.EMPTY; } - if (className.length() == 0) { + if( className.length() == 0 ) + { return StringUtils.EMPTY; } char[] chars = className.toCharArray(); int lastDot = 0; - for (int i = 0; i < chars.length; i++) { - if (chars[i] == PACKAGE_SEPARATOR_CHAR) { + for( int i = 0; i < chars.length; i++ ) + { + if( chars[i] == PACKAGE_SEPARATOR_CHAR ) + { lastDot = i + 1; - } else if (chars[i] == INNER_CLASS_SEPARATOR_CHAR) { // handle inner classes + } + else if( chars[i] == INNER_CLASS_SEPARATOR_CHAR ) + { // handle inner classes chars[i] = PACKAGE_SEPARATOR_CHAR; } } - return new String(chars, lastDot, chars.length - lastDot); + return new String( chars, lastDot, chars.length - lastDot ); } - + // Package name // ---------------------------------------------------------------------- + /** *

Gets the package name of an Object.

- * - * @param object the class to get the package name for, may be null - * @param valueIfNull the value to return if null + * + * @param object the class to get the package name for, may be null + * @param valueIfNull the value to return if null * @return the package name of the object, or the null value */ - public static String getPackageName(Object object, String valueIfNull) { - if (object == null) { + public static String getPackageName( Object object, String valueIfNull ) + { + if( object == null ) + { return valueIfNull; } - return getPackageName(object.getClass().getName()); + return getPackageName( object.getClass().getName() ); } - + /** *

Gets the package name of a Class.

- * - * @param cls the class to get the package name for, may be null. + * + * @param cls the class to get the package name for, may be null. * @return the package name or an empty string */ - public static String getPackageName(Class cls) { - if (cls == null) { + public static String getPackageName( Class cls ) + { + if( cls == null ) + { return StringUtils.EMPTY; } - return getPackageName(cls.getName()); + return getPackageName( cls.getName() ); } - + /** *

Gets the package name from a String.

+ *

+ *

The string passed in is assumed to be a class name - it is not checked.

If the class is unpackaged, + * return an empty string.

* - *

The string passed in is assumed to be a class name - it is not checked.

- *

If the class is unpackaged, return an empty string.

- * - * @param className the className to get the package name for, may be null + * @param className the className to get the package name for, may be null * @return the package name or an empty string */ - public static String getPackageName(String className) { - if (className == null) { + public static String getPackageName( String className ) + { + if( className == null ) + { return StringUtils.EMPTY; } - int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); - if (i == -1) { + int i = className.lastIndexOf( PACKAGE_SEPARATOR_CHAR ); + if( i == -1 ) + { return StringUtils.EMPTY; } - return className.substring(0, i); + return className.substring( 0, i ); } - + // Superclasses/Superinterfaces // ---------------------------------------------------------------------- + /** *

Gets a List of superclasses for the given class.

- * - * @param cls the class to look up, may be null - * @return the List of superclasses in order going up from this one - * null if null input + * + * @param cls the class to look up, may be null + * @return the List of superclasses in order going up from this one null if null input */ - public static List getAllSuperclasses(Class cls) { - if (cls == null) { + public static List getAllSuperclasses( Class cls ) + { + if( cls == null ) + { return null; } List classes = new ArrayList(); Class superclass = cls.getSuperclass(); - while (superclass != null) { - classes.add(superclass); + while( superclass != null ) + { + classes.add( superclass ); superclass = superclass.getSuperclass(); } return classes; } - + /** - *

Gets a List of all interfaces implemented by the given - * class and its superclasses.

+ *

Gets a List of all interfaces implemented by the given class and its superclasses.

+ *

+ *

The order is determined by looking through each interface in turn as declared in the source file and following + * its hierarchy up. Then each superclass is considered in the same way. Later duplicates are ignored, so the order + * is maintained.

* - *

The order is determined by looking through each interface in turn as - * declared in the source file and following its hierarchy up. Then each - * superclass is considered in the same way. Later duplicates are ignored, - * so the order is maintained.

- * - * @param cls the class to look up, may be null - * @return the List of interfaces in order, - * null if null input + * @param cls the class to look up, may be null + * @return the List of interfaces in order, null if null input */ - public static List getAllInterfaces(Class cls) { - if (cls == null) { + public static List getAllInterfaces( Class cls ) + { + if( cls == null ) + { return null; } List list = new ArrayList(); - while (cls != null) { + while( cls != null ) + { Class[] interfaces = cls.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (list.contains(interfaces[i]) == false) { - list.add(interfaces[i]); + for( int i = 0; i < interfaces.length; i++ ) + { + if( list.contains( interfaces[i] ) == false ) + { + list.add( interfaces[i] ); } - List superInterfaces = getAllInterfaces(interfaces[i]); - for (Iterator it = superInterfaces.iterator(); it.hasNext();) { - Class intface = (Class) it.next(); - if (list.contains(intface) == false) { - list.add(intface); + List superInterfaces = getAllInterfaces( interfaces[i] ); + for( Iterator it = superInterfaces.iterator(); it.hasNext(); ) + { + Class intface = ( Class ) it.next(); + if( list.contains( intface ) == false ) + { + list.add( intface ); } } } @@ -247,241 +288,262 @@ public class ClassUtils { } return list; } - + // Convert list // ---------------------------------------------------------------------- + /** *

Given a List of class names, this method converts them into classes.

+ *

+ *

A new List is returned. If the class name cannot be found, null is stored in the + * List. If the class name in the List is null, null is stored + * in the output List.

* - *

A new List is returned. If the class name cannot be found, null - * is stored in the List. If the class name in the List is - * null, null is stored in the output List.

- * - * @param classNames the classNames to change - * @return a List of Class objects corresponding to the class names, - * null if null input + * @param classNames the classNames to change + * @return a List of Class objects corresponding to the class names, null if null input * @throws ClassCastException if classNames contains a non String entry */ - public static List convertClassNamesToClasses(List classNames) { - if (classNames == null) { + public static List convertClassNamesToClasses( List classNames ) + { + if( classNames == null ) + { return null; } - List classes = new ArrayList(classNames.size()); - for (Iterator it = classNames.iterator(); it.hasNext();) { - String className = (String) it.next(); - try { - classes.add(Class.forName(className)); - } catch (Exception ex) { - classes.add(null); + List classes = new ArrayList( classNames.size() ); + for( Iterator it = classNames.iterator(); it.hasNext(); ) + { + String className = ( String ) it.next(); + try + { + classes.add( Class.forName( className ) ); + } + catch( Exception ex ) + { + classes.add( null ); } } return classes; } - + /** - *

Given a List of Class objects, this method converts - * them into class names.

+ *

Given a List of Class objects, this method converts them into class names.

+ *

+ *

A new List is returned. null objects will be copied into the returned list as + * null.

* - *

A new List is returned. null objects will be copied into - * the returned list as null.

- * - * @param classes the classes to change - * @return a List of class names corresponding to the Class objects, - * null if null input + * @param classes the classes to change + * @return a List of class names corresponding to the Class objects, null if null input * @throws ClassCastException if classes contains a non-Class entry */ - public static List convertClassesToClassNames(List classes) { - if (classes == null) { + public static List convertClassesToClassNames( List classes ) + { + if( classes == null ) + { return null; } - List classNames = new ArrayList(classes.size()); - for (Iterator it = classes.iterator(); it.hasNext();) { - Class cls = (Class) it.next(); - if (cls == null) { - classNames.add(null); - } else { - classNames.add(cls.getName()); + List classNames = new ArrayList( classes.size() ); + for( Iterator it = classes.iterator(); it.hasNext(); ) + { + Class cls = ( Class ) it.next(); + if( cls == null ) + { + classNames.add( null ); + } + else + { + classNames.add( cls.getName() ); } } return classNames; } - + // Is assignable // ---------------------------------------------------------------------- + /** *

Checks if an array of Classes can be assigned to another array of Classes.

+ *

+ *

This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It + * can be used to check if a set of arguments (the first parameter) are suitably compatible with a set of method + * parameter types (the second parameter).

+ *

+ *

Unlike the {@link Class#isAssignableFrom(Class)} method, this method takes into account widenings of primitive + * classes and nulls.

+ *

+ *

Primitive widenings allow an int to be assigned to a long, float or + * double. This method returns the correct result for these cases.

+ *

+ *

Null may be assigned to any reference type. This method will return true if + * null is passed in and the toClass is non-primitive.

+ *

+ *

Specifically, this method tests whether the type represented by the specified Class parameter can + * be converted to the type represented by this Class object via an identity conversion widening + * primitive or widening reference conversion. See The Java + * Language Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.

* - *

This method calls {@link #isAssignable(Class, Class) isAssignable} for each - * Class pair in the input arrays. It can be used to check if a set of arguments - * (the first parameter) are suitably compatible with a set of method parameter types - * (the second parameter).

- * - *

Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this - * method takes into account widenings of primitive classes and - * nulls.

- * - *

Primitive widenings allow an int to be assigned to a long, - * float or double. This method returns the correct - * result for these cases.

- * - *

Null may be assigned to any reference type. This method will - * return true if null is passed in and the toClass is - * non-primitive.

- * - *

Specifically, this method tests whether the type represented by the - * specified Class parameter can be converted to the type - * represented by this Class object via an identity conversion - * widening primitive or widening reference conversion. See - * The Java Language Specification, - * sections 5.1.1, 5.1.2 and 5.1.4 for details.

- * - * @param classArray the array of Classes to check, may be null - * @param toClassArray the array of Classes to try to assign into, may be null + * @param classArray the array of Classes to check, may be null + * @param toClassArray the array of Classes to try to assign into, may be null * @return true if assignment possible */ - public static boolean isAssignable(Class[] classArray, Class[] toClassArray) { - if (ArrayUtils.isSameLength(classArray, toClassArray) == false) { + public static boolean isAssignable( Class[] classArray, Class[] toClassArray ) + { + if( ArrayUtils.isSameLength( classArray, toClassArray ) == false ) + { return false; } - if (classArray == null) { + if( classArray == null ) + { classArray = ArrayUtils.EMPTY_CLASS_ARRAY; } - if (toClassArray == null) { + if( toClassArray == null ) + { toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY; } - for (int i = 0; i < classArray.length; i++) { - if (isAssignable(classArray[i], toClassArray[i]) == false) { + for( int i = 0; i < classArray.length; i++ ) + { + if( isAssignable( classArray[i], toClassArray[i] ) == false ) + { return false; } } return true; } - + /** - *

Checks if one Class can be assigned to a variable of - * another Class.

+ *

Checks if one Class can be assigned to a variable of another Class.

+ *

+ *

Unlike the {@link Class#isAssignableFrom(Class)} method, this method takes into account widenings of primitive + * classes and nulls.

+ *

+ *

Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct + * result for these cases.

+ *

+ *

Null may be assigned to any reference type. This method will return true if + * null is passed in and the toClass is non-primitive.

+ *

+ *

Specifically, this method tests whether the type represented by the specified Class parameter can + * be converted to the type represented by this Class object via an identity conversion widening + * primitive or widening reference conversion. See The Java + * Language Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.

* - *

Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, - * this method takes into account widenings of primitive classes and - * nulls.

- * - *

Primitive widenings allow an int to be assigned to a long, float or - * double. This method returns the correct result for these cases.

- * - *

Null may be assigned to any reference type. This method - * will return true if null is passed in and the - * toClass is non-primitive.

- * - *

Specifically, this method tests whether the type represented by the - * specified Class parameter can be converted to the type - * represented by this Class object via an identity conversion - * widening primitive or widening reference conversion. See - * The Java Language Specification, - * sections 5.1.1, 5.1.2 and 5.1.4 for details.

- * - * @param cls the Class to check, may be null - * @param toClass the Class to try to assign into, returns false if null + * @param cls the Class to check, may be null + * @param toClass the Class to try to assign into, returns false if null * @return true if assignment possible */ - public static boolean isAssignable(Class cls, Class toClass) { - if (toClass == null) { + public static boolean isAssignable( Class cls, Class toClass ) + { + if( toClass == null ) + { return false; } // have to check for null, as isAssignableFrom doesn't - if (cls == null) { - return !(toClass.isPrimitive()); + if( cls == null ) + { + return !( toClass.isPrimitive() ); } - if (cls.equals(toClass)) { + if( cls.equals( toClass ) ) + { return true; } - if (cls.isPrimitive()) { - if (toClass.isPrimitive() == false) { + if( cls.isPrimitive() ) + { + if( toClass.isPrimitive() == false ) + { return false; } - if (Integer.TYPE.equals(cls)) { - return Long.TYPE.equals(toClass) - || Float.TYPE.equals(toClass) - || Double.TYPE.equals(toClass); + if( Integer.TYPE.equals( cls ) ) + { + return Long.TYPE.equals( toClass ) + || Float.TYPE.equals( toClass ) + || Double.TYPE.equals( toClass ); } - if (Long.TYPE.equals(cls)) { - return Float.TYPE.equals(toClass) - || Double.TYPE.equals(toClass); + if( Long.TYPE.equals( cls ) ) + { + return Float.TYPE.equals( toClass ) + || Double.TYPE.equals( toClass ); } - if (Boolean.TYPE.equals(cls)) { + if( Boolean.TYPE.equals( cls ) ) + { return false; } - if (Double.TYPE.equals(cls)) { + if( Double.TYPE.equals( cls ) ) + { return false; } - if (Float.TYPE.equals(cls)) { - return Double.TYPE.equals(toClass); + if( Float.TYPE.equals( cls ) ) + { + return Double.TYPE.equals( toClass ); } - if (Character.TYPE.equals(cls)) { - return Integer.TYPE.equals(toClass) - || Long.TYPE.equals(toClass) - || Float.TYPE.equals(toClass) - || Double.TYPE.equals(toClass); + if( Character.TYPE.equals( cls ) ) + { + return Integer.TYPE.equals( toClass ) + || Long.TYPE.equals( toClass ) + || Float.TYPE.equals( toClass ) + || Double.TYPE.equals( toClass ); } - if (Short.TYPE.equals(cls)) { - return Integer.TYPE.equals(toClass) - || Long.TYPE.equals(toClass) - || Float.TYPE.equals(toClass) - || Double.TYPE.equals(toClass); + if( Short.TYPE.equals( cls ) ) + { + return Integer.TYPE.equals( toClass ) + || Long.TYPE.equals( toClass ) + || Float.TYPE.equals( toClass ) + || Double.TYPE.equals( toClass ); } - if (Byte.TYPE.equals(cls)) { - return Short.TYPE.equals(toClass) - || Integer.TYPE.equals(toClass) - || Long.TYPE.equals(toClass) - || Float.TYPE.equals(toClass) - || Double.TYPE.equals(toClass); + if( Byte.TYPE.equals( cls ) ) + { + return Short.TYPE.equals( toClass ) + || Integer.TYPE.equals( toClass ) + || Long.TYPE.equals( toClass ) + || Float.TYPE.equals( toClass ) + || Double.TYPE.equals( toClass ); } // should never get here return false; } - return toClass.isAssignableFrom(cls); + return toClass.isAssignableFrom( cls ); } - + /** - *

Converts the specified primitive Class object to its corresponding - * wrapper Class object.

- * - *

NOTE: From v2.2, this method handles Void.TYPE, - * returning Void.TYPE.

+ *

Converts the specified primitive Class object to its corresponding wrapper Class object.

+ *

+ *

NOTE: From v2.2, this method handles Void.TYPE, returning Void.TYPE.

* - * @param cls the class to convert, may be null - * @return the wrapper class for cls or cls if - * cls is not a primitive. null if null input. + * @param cls the class to convert, may be null + * @return the wrapper class for cls or cls if cls is not a primitive. + * null if null input. * @since 2.1 */ - public static Class primitiveToWrapper(Class cls) { + public static Class primitiveToWrapper( Class cls ) + { Class convertedClass = cls; - if (cls != null && cls.isPrimitive()) { - convertedClass = (Class) primitiveWrapperMap.get(cls); - } + if( cls != null && cls.isPrimitive() ) + { + convertedClass = ( Class ) primitiveWrapperMap.get( cls ); + } return convertedClass; } /** - *

Converts the specified array of primitive Class objects to an array of - * its corresponding wrapper Class objects.

+ *

Converts the specified array of primitive Class objects to an array of its corresponding wrapper Class + * objects.

* - * @param classes the class array to convert, may be null or empty - * @return an array which contains for each given class, the wrapper class or - * the original class if class is not a primitive. null if null input. - * Empty array if an empty array passed in. + * @param classes the class array to convert, may be null or empty + * @return an array which contains for each given class, the wrapper class or the original class if class is not a + * primitive. null if null input. Empty array if an empty array passed in. * @since 2.1 */ - public static Class[] primitivesToWrappers(Class[] classes) { - if (classes == null) { + public static Class[] primitivesToWrappers( Class[] classes ) + { + if( classes == null ) + { return null; } - - if (classes.length == 0) { + if( classes.length == 0 ) + { return classes; } - Class[] convertedClasses = new Class[classes.length]; - for (int i=0; i < classes.length; i++) { + for( int i = 0; i < classes.length; i++ ) + { convertedClasses[i] = primitiveToWrapper( classes[i] ); } return convertedClasses; @@ -489,18 +551,120 @@ public class ClassUtils { // Inner class // ---------------------------------------------------------------------- + /** *

Is the specified class an inner class or static nested class.

- * - * @param cls the class to check, may be null - * @return true if the class is an inner or static nested class, - * false if not or null + * + * @param cls the class to check, may be null + * @return true if the class is an inner or static nested class, false if not or null */ - public static boolean isInnerClass(Class cls) { - if (cls == null) { + public static boolean isInnerClass( Class cls ) + { + if( cls == null ) + { return false; } - return cls.getName().indexOf(INNER_CLASS_SEPARATOR_CHAR) >= 0; + return cls.getName().indexOf( INNER_CLASS_SEPARATOR_CHAR ) >= 0; } + /** + * Returns the class represented by className using the classLoader. This implementation + * supports names like "java.lang.String[]" as well as "[Ljava.lang.String;". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by className using the classLoader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass( ClassLoader classLoader, String className, boolean initialize ) + throws ClassNotFoundException + { + Class clazz; + if( abbreviationMap.containsKey( className ) ) + { + clazz = Class.forName( "[" + abbreviationMap.get( className ), initialize, classLoader ).getComponentType(); + } + else + { + clazz = Class.forName( toProperClassName( className ), initialize, classLoader ); + } + return clazz; + } + + /** + * Returns the (initialized) class represented by className using the classLoader. This + * implementation supports names like "java.lang.String[]" as well as + * "[Ljava.lang.String;". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @return the class represented by className using the classLoader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass( ClassLoader classLoader, String className ) throws ClassNotFoundException + { + return getClass( classLoader, className, true ); + } + + /** + * Returns the (initialized )class represented by className using the current thread's context class + * loader. This implementation supports names like "java.lang.String[]" as well as + * "[Ljava.lang.String;". + * + * @param className the class name + * @return the class represented by className using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass( String className ) throws ClassNotFoundException + { + return getClass( Thread.currentThread().getContextClassLoader() == null ? ClassUtils.class.getClassLoader() : + Thread.currentThread().getContextClassLoader(), className, true ); + } + + /** + * Returns the class represented by className using the current thread's context class loader. This + * implementation supports names like "java.lang.String[]" as well as + * "[Ljava.lang.String;". + * + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by className using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass( String className, boolean initialize ) throws ClassNotFoundException + { + return getClass( Thread.currentThread().getContextClassLoader() == null ? ClassUtils.class.getClassLoader() : + Thread.currentThread().getContextClassLoader(), className, initialize ); + } + + private static String toProperClassName( String className ) + { + className = StringUtils.deleteWhitespace( className ); + if( className == null ) + { + throw new NullArgumentException( "className" ); + } + else if( className.endsWith( "[]" ) ) + { + final StringBuffer classNameBuffer = new StringBuffer(); + while( className.endsWith( "[]" ) ) + { + className = className.substring( 0, className.length() - 2 ); + classNameBuffer.append( "[" ); + } + final String abbreviation = ( String ) abbreviationMap.get( className ); + if( abbreviation != null ) + { + classNameBuffer.append( abbreviation ); + } + else + { + classNameBuffer.append( "L" ).append( className ).append( ";" ); + } + className = classNameBuffer.toString(); + + } + return className; + } } diff --git a/src/test/org/apache/commons/lang/ClassUtilsTest.java b/src/test/org/apache/commons/lang/ClassUtilsTest.java index 31ca69455..c8d2f22d6 100644 --- a/src/test/org/apache/commons/lang/ClassUtilsTest.java +++ b/src/test/org/apache/commons/lang/ClassUtilsTest.java @@ -392,6 +392,110 @@ public class ClassUtilsTest extends TestCase { assertNotSame("unmodified", noPrimitives, ClassUtils.primitivesToWrappers(noPrimitives)); } + public void testGetClassClassNotFound() throws Exception { + assertGetClassThrowsClassNotFound( "bool" ); + assertGetClassThrowsClassNotFound( "bool[]" ); + assertGetClassThrowsClassNotFound( "integer[]" ); + } + + public void testGetClassInvalidArguments() throws Exception { + assertGetClassThrowsIllegalArgument( null ); + assertGetClassThrowsClassNotFound( "[][][]" ); + assertGetClassThrowsClassNotFound( "[[]" ); + assertGetClassThrowsClassNotFound( "[" ); + assertGetClassThrowsClassNotFound( "java.lang.String][" ); + assertGetClassThrowsClassNotFound( ".hello.world" ); + assertGetClassThrowsClassNotFound( "hello..world" ); + } + + public void testWithInterleavingWhitespace() throws ClassNotFoundException { + assertEquals( int[].class, ClassUtils.getClass( " int [ ] " ) ); + assertEquals( long[].class, ClassUtils.getClass( "\rlong\t[\n]\r" ) ); + assertEquals( short[].class, ClassUtils.getClass( "\tshort \t\t[]" ) ); + assertEquals( byte[].class, ClassUtils.getClass( "byte[\t\t\n\r] " ) ); + } + + public void testGetClassByNormalNameArrays() throws ClassNotFoundException { + assertEquals( int[].class, ClassUtils.getClass( "int[]" ) ); + assertEquals( long[].class, ClassUtils.getClass( "long[]" ) ); + assertEquals( short[].class, ClassUtils.getClass( "short[]" ) ); + assertEquals( byte[].class, ClassUtils.getClass( "byte[]" ) ); + assertEquals( char[].class, ClassUtils.getClass( "char[]" ) ); + assertEquals( float[].class, ClassUtils.getClass( "float[]" ) ); + assertEquals( double[].class, ClassUtils.getClass( "double[]" ) ); + assertEquals( boolean[].class, ClassUtils.getClass( "boolean[]" ) ); + assertEquals( String[].class, ClassUtils.getClass( "java.lang.String[]" ) ); + } + + public void testGetClassByNormalNameArrays2D() throws ClassNotFoundException { + assertEquals( int[][].class, ClassUtils.getClass( "int[][]" ) ); + assertEquals( long[][].class, ClassUtils.getClass( "long[][]" ) ); + assertEquals( short[][].class, ClassUtils.getClass( "short[][]" ) ); + assertEquals( byte[][].class, ClassUtils.getClass( "byte[][]" ) ); + assertEquals( char[][].class, ClassUtils.getClass( "char[][]" ) ); + assertEquals( float[][].class, ClassUtils.getClass( "float[][]" ) ); + assertEquals( double[][].class, ClassUtils.getClass( "double[][]" ) ); + assertEquals( boolean[][].class, ClassUtils.getClass( "boolean[][]" ) ); + assertEquals( String[][].class, ClassUtils.getClass( "java.lang.String[][]" ) ); + } + + public void testGetClassWithArrayClasses2D() throws Exception { + assertGetClassReturnsClass( String[][].class ); + assertGetClassReturnsClass( int[][].class ); + assertGetClassReturnsClass( long[][].class ); + assertGetClassReturnsClass( short[][].class ); + assertGetClassReturnsClass( byte[][].class ); + assertGetClassReturnsClass( char[][].class ); + assertGetClassReturnsClass( float[][].class ); + assertGetClassReturnsClass( double[][].class ); + assertGetClassReturnsClass( boolean[][].class ); + } + + public void testGetClassWithArrayClasses() throws Exception { + assertGetClassReturnsClass( String[].class ); + assertGetClassReturnsClass( int[].class ); + assertGetClassReturnsClass( long[].class ); + assertGetClassReturnsClass( short[].class ); + assertGetClassReturnsClass( byte[].class ); + assertGetClassReturnsClass( char[].class ); + assertGetClassReturnsClass( float[].class ); + assertGetClassReturnsClass( double[].class ); + assertGetClassReturnsClass( boolean[].class ); + } + + public void testGetClassRawPrimitives() throws ClassNotFoundException { + assertEquals( int.class, ClassUtils.getClass( "int" ) ); + assertEquals( long.class, ClassUtils.getClass( "long" ) ); + assertEquals( short.class, ClassUtils.getClass( "short" ) ); + assertEquals( byte.class, ClassUtils.getClass( "byte" ) ); + assertEquals( char.class, ClassUtils.getClass( "char" ) ); + assertEquals( float.class, ClassUtils.getClass( "float" ) ); + assertEquals( double.class, ClassUtils.getClass( "double" ) ); + assertEquals( boolean.class, ClassUtils.getClass( "boolean" ) ); + } + + private void assertGetClassReturnsClass( Class c ) throws Exception { + assertEquals( c, ClassUtils.getClass( c.getName() ) ); + } + + private void assertGetClassThrowsException( String className, Class exceptionType ) throws Exception { + try { + ClassUtils.getClass( className ); + fail( "ClassUtils.getClass() should fail with an exception of type " + exceptionType.getName() + " when given class name \"" + className + "\"." ); + } + catch( Exception e ) { + assertTrue( exceptionType.isAssignableFrom( e.getClass() ) ); + } + } + + private void assertGetClassThrowsIllegalArgument( String className ) throws Exception { + assertGetClassThrowsException( className, IllegalArgumentException.class ); + } + + private void assertGetClassThrowsClassNotFound( String className ) throws Exception { + assertGetClassThrowsException( className, ClassNotFoundException.class ); + } + /** * Creates a new instance of URLClassLoader with the system class loader's URLs and a null parent * class loader.