You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2008/03/19 05:27:42 UTC

svn commit: r638702 - in /commons/proper/lang/branches/LANG_POST_2_4/src: java/org/apache/commons/lang/ClassUtils.java test/org/apache/commons/lang/ClassUtilsTest.java

Author: mbenson
Date: Tue Mar 18 21:27:41 2008
New Revision: 638702

URL: http://svn.apache.org/viewvc?rev=638702&view=rev
Log:
isAssignable with autoboxing

Modified:
    commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ClassUtils.java
    commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/ClassUtilsTest.java

Modified: commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ClassUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ClassUtils.java?rev=638702&r1=638701&r2=638702&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ClassUtils.java (original)
+++ commons/proper/lang/branches/LANG_POST_2_4/src/java/org/apache/commons/lang/ClassUtils.java Tue Mar 18 21:27:41 2008
@@ -393,6 +393,42 @@
      * @return <code>true</code> if assignment possible
      */
     public static boolean isAssignable(Class[] classArray, Class[] toClassArray) {
+        return isAssignable(classArray, toClassArray, false);
+    }
+
+    /**
+     * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
+     *
+     * <p>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).</p>
+     *
+     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
+     * method takes into account widenings of primitive classes and
+     * <code>null</code>s.</p>
+     *
+     * <p>Primitive widenings allow an int to be assigned to a <code>long</code>,
+     * <code>float</code> or <code>double</code>. This method returns the correct
+     * result for these cases.</p>
+     *
+     * <p><code>Null</code> may be assigned to any reference type. This method will
+     * return <code>true</code> if <code>null</code> is passed in and the toClass is
+     * non-primitive.</p>
+     *
+     * <p>Specifically, this method tests whether the type represented by the
+     * specified <code>Class</code> parameter can be converted to the type
+     * represented by this <code>Class</code> object via an identity conversion
+     * widening primitive or widening reference conversion. See
+     * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
+     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
+     *
+     * @param classArray  the array of Classes to check, may be <code>null</code>
+     * @param toClassArray  the array of Classes to try to assign into, may be <code>null</code>
+     * @param autoboxing  whether to use implicit autoboxing/unboxing between primitives and wrappers
+     * @return <code>true</code> if assignment possible
+     */
+    public static boolean isAssignable(Class[] classArray, Class[] toClassArray, boolean autoboxing) {
         if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
             return false;
         }
@@ -403,7 +439,7 @@
             toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
         }
         for (int i = 0; i < classArray.length; i++) {
-            if (isAssignable(classArray[i], toClassArray[i]) == false) {
+            if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) {
                 return false;
             }
         }
@@ -437,12 +473,58 @@
      * @return <code>true</code> if assignment possible
      */
     public static boolean isAssignable(Class cls, Class toClass) {
+        return isAssignable(cls, toClass, false);
+    }
+
+    /**
+     * <p>Checks if one <code>Class</code> can be assigned to a variable of
+     * another <code>Class</code>.</p>
+     *
+     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
+     * this method takes into account widenings of primitive classes and
+     * <code>null</code>s.</p>
+     *
+     * <p>Primitive widenings allow an int to be assigned to a long, float or
+     * double. This method returns the correct result for these cases.</p>
+     *
+     * <p><code>Null</code> may be assigned to any reference type. This method
+     * will return <code>true</code> if <code>null</code> is passed in and the
+     * toClass is non-primitive.</p>
+     *
+     * <p>Specifically, this method tests whether the type represented by the
+     * specified <code>Class</code> parameter can be converted to the type
+     * represented by this <code>Class</code> object via an identity conversion
+     * widening primitive or widening reference conversion. See
+     * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
+     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
+     *
+     * @param cls  the Class to check, may be null
+     * @param toClass  the Class to try to assign into, returns false if null
+     * @param autoboxing  whether to use implicit autoboxing/unboxing between primitives and wrappers
+     * @return <code>true</code> if assignment possible
+     */
+    public static boolean isAssignable(Class cls, Class toClass, boolean autoboxing) {
         if (toClass == null) {
             return false;
         }
         // have to check for null, as isAssignableFrom doesn't
         if (cls == null) {
             return !(toClass.isPrimitive());
+        }
+        //autoboxing:
+        if (autoboxing) {
+            if (cls.isPrimitive() && !toClass.isPrimitive()) {
+                cls = primitiveToWrapper(cls);
+                if (cls == null) {
+                    return false;
+                }
+            }
+            if (toClass.isPrimitive() && !cls.isPrimitive()) {
+                cls = wrapperToPrimitive(cls);
+                if (cls == null) {
+                    return false;
+                }
+            }
         }
         if (cls.equals(toClass)) {
             return true;

Modified: commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/ClassUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/ClassUtilsTest.java?rev=638702&r1=638701&r2=638702&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/ClassUtilsTest.java (original)
+++ commons/proper/lang/branches/LANG_POST_2_4/src/test/org/apache/commons/lang/ClassUtilsTest.java Tue Mar 18 21:27:41 2008
@@ -254,6 +254,26 @@
         assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.class));
     }
     
+    public void test_isAssignable_Autoboxing() throws Exception {
+        assertFalse(ClassUtils.isAssignable((Class) null, null, true));
+        assertFalse(ClassUtils.isAssignable(String.class, null, true));
+
+        assertTrue(ClassUtils.isAssignable(null, Object.class, true));
+        assertTrue(ClassUtils.isAssignable(null, Integer.class, true));
+        assertFalse(ClassUtils.isAssignable(null, Integer.TYPE, true));
+        assertTrue(ClassUtils.isAssignable(String.class, Object.class, true));
+        assertTrue(ClassUtils.isAssignable(String.class, String.class, true));
+        assertFalse(ClassUtils.isAssignable(Object.class, String.class, true));
+        assertTrue(ClassUtils.isAssignable(Integer.TYPE, Integer.class, true));
+        assertTrue(ClassUtils.isAssignable(Integer.class, Integer.TYPE, true));
+        assertTrue(ClassUtils.isAssignable(Integer.TYPE, Integer.TYPE, true));
+        assertTrue(ClassUtils.isAssignable(Integer.class, Integer.class, true));
+        assertTrue(ClassUtils.isAssignable(Boolean.TYPE, Boolean.class, true));
+        assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.TYPE, true));
+        assertTrue(ClassUtils.isAssignable(Boolean.TYPE, Boolean.TYPE, true));
+        assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.class, true));
+    }
+
     public void test_isAssignable_Widening() throws Exception {
         // test byte conversions
         assertFalse("byte -> char", ClassUtils.isAssignable(Byte.TYPE, Character.TYPE));
@@ -334,6 +354,88 @@
         assertFalse("boolean -> float", ClassUtils.isAssignable(Boolean.TYPE, Float.TYPE));
         assertFalse("boolean -> double", ClassUtils.isAssignable(Boolean.TYPE, Double.TYPE));
         assertTrue("boolean -> boolean", ClassUtils.isAssignable(Boolean.TYPE, Boolean.TYPE));
+    }
+    
+    public void test_isAssignable_Unboxing_Widening() throws Exception {
+        // test byte conversions
+        assertFalse("byte -> char", ClassUtils.isAssignable(Byte.class, Character.TYPE, true));
+        assertTrue("byte -> byte", ClassUtils.isAssignable(Byte.class, Byte.TYPE, true));
+        assertTrue("byte -> short", ClassUtils.isAssignable(Byte.class, Short.TYPE, true));
+        assertTrue("byte -> int", ClassUtils.isAssignable(Byte.class, Integer.TYPE, true));
+        assertTrue("byte -> long", ClassUtils.isAssignable(Byte.class, Long.TYPE, true));
+        assertTrue("byte -> float", ClassUtils.isAssignable(Byte.class, Float.TYPE, true));
+        assertTrue("byte -> double", ClassUtils.isAssignable(Byte.class, Double.TYPE, true));
+        assertFalse("byte -> boolean", ClassUtils.isAssignable(Byte.class, Boolean.TYPE, true));
+        
+        // test short conversions
+        assertFalse("short -> char", ClassUtils.isAssignable(Short.class, Character.TYPE, true));
+        assertFalse("short -> byte", ClassUtils.isAssignable(Short.class, Byte.TYPE, true));
+        assertTrue("short -> short", ClassUtils.isAssignable(Short.class, Short.TYPE, true));
+        assertTrue("short -> int", ClassUtils.isAssignable(Short.class, Integer.TYPE, true));
+        assertTrue("short -> long", ClassUtils.isAssignable(Short.class, Long.TYPE, true));
+        assertTrue("short -> float", ClassUtils.isAssignable(Short.class, Float.TYPE, true));
+        assertTrue("short -> double", ClassUtils.isAssignable(Short.class, Double.TYPE, true));
+        assertFalse("short -> boolean", ClassUtils.isAssignable(Short.class, Boolean.TYPE, true));
+        
+        // test char conversions
+        assertTrue("char -> char", ClassUtils.isAssignable(Character.class, Character.TYPE, true));
+        assertFalse("char -> byte", ClassUtils.isAssignable(Character.class, Byte.TYPE, true));
+        assertFalse("char -> short", ClassUtils.isAssignable(Character.class, Short.TYPE, true));
+        assertTrue("char -> int", ClassUtils.isAssignable(Character.class, Integer.TYPE, true));
+        assertTrue("char -> long", ClassUtils.isAssignable(Character.class, Long.TYPE, true));
+        assertTrue("char -> float", ClassUtils.isAssignable(Character.class, Float.TYPE, true));
+        assertTrue("char -> double", ClassUtils.isAssignable(Character.class, Double.TYPE, true));
+        assertFalse("char -> boolean", ClassUtils.isAssignable(Character.class, Boolean.TYPE, true));
+        
+        // test int conversions
+        assertFalse("int -> char", ClassUtils.isAssignable(Integer.class, Character.TYPE, true));
+        assertFalse("int -> byte", ClassUtils.isAssignable(Integer.class, Byte.TYPE, true));
+        assertFalse("int -> short", ClassUtils.isAssignable(Integer.class, Short.TYPE, true));
+        assertTrue("int -> int", ClassUtils.isAssignable(Integer.class, Integer.TYPE, true));
+        assertTrue("int -> long", ClassUtils.isAssignable(Integer.class, Long.TYPE, true));
+        assertTrue("int -> float", ClassUtils.isAssignable(Integer.class, Float.TYPE, true));
+        assertTrue("int -> double", ClassUtils.isAssignable(Integer.class, Double.TYPE, true));
+        assertFalse("int -> boolean", ClassUtils.isAssignable(Integer.class, Boolean.TYPE, true));
+        
+        // test long conversions
+        assertFalse("long -> char", ClassUtils.isAssignable(Long.class, Character.TYPE, true));
+        assertFalse("long -> byte", ClassUtils.isAssignable(Long.class, Byte.TYPE, true));
+        assertFalse("long -> short", ClassUtils.isAssignable(Long.class, Short.TYPE, true));
+        assertFalse("long -> int", ClassUtils.isAssignable(Long.class, Integer.TYPE, true));
+        assertTrue("long -> long", ClassUtils.isAssignable(Long.class, Long.TYPE, true));
+        assertTrue("long -> float", ClassUtils.isAssignable(Long.class, Float.TYPE, true));
+        assertTrue("long -> double", ClassUtils.isAssignable(Long.class, Double.TYPE, true));
+        assertFalse("long -> boolean", ClassUtils.isAssignable(Long.class, Boolean.TYPE, true));
+        
+        // test float conversions
+        assertFalse("float -> char", ClassUtils.isAssignable(Float.class, Character.TYPE, true));
+        assertFalse("float -> byte", ClassUtils.isAssignable(Float.class, Byte.TYPE, true));
+        assertFalse("float -> short", ClassUtils.isAssignable(Float.class, Short.TYPE, true));
+        assertFalse("float -> int", ClassUtils.isAssignable(Float.class, Integer.TYPE, true));
+        assertFalse("float -> long", ClassUtils.isAssignable(Float.class, Long.TYPE, true));
+        assertTrue("float -> float", ClassUtils.isAssignable(Float.class, Float.TYPE, true));
+        assertTrue("float -> double", ClassUtils.isAssignable(Float.class, Double.TYPE, true));
+        assertFalse("float -> boolean", ClassUtils.isAssignable(Float.class, Boolean.TYPE, true));
+        
+        // test double conversions
+        assertFalse("double -> char", ClassUtils.isAssignable(Double.class, Character.TYPE, true));
+        assertFalse("double -> byte", ClassUtils.isAssignable(Double.class, Byte.TYPE, true));
+        assertFalse("double -> short", ClassUtils.isAssignable(Double.class, Short.TYPE, true));
+        assertFalse("double -> int", ClassUtils.isAssignable(Double.class, Integer.TYPE, true));
+        assertFalse("double -> long", ClassUtils.isAssignable(Double.class, Long.TYPE, true));
+        assertFalse("double -> float", ClassUtils.isAssignable(Double.class, Float.TYPE, true));
+        assertTrue("double -> double", ClassUtils.isAssignable(Double.class, Double.TYPE, true));
+        assertFalse("double -> boolean", ClassUtils.isAssignable(Double.class, Boolean.TYPE, true));
+        
+        // test boolean conversions
+        assertFalse("boolean -> char", ClassUtils.isAssignable(Boolean.class, Character.TYPE, true));
+        assertFalse("boolean -> byte", ClassUtils.isAssignable(Boolean.class, Byte.TYPE, true));
+        assertFalse("boolean -> short", ClassUtils.isAssignable(Boolean.class, Short.TYPE, true));
+        assertFalse("boolean -> int", ClassUtils.isAssignable(Boolean.class, Integer.TYPE, true));
+        assertFalse("boolean -> long", ClassUtils.isAssignable(Boolean.class, Long.TYPE, true));
+        assertFalse("boolean -> float", ClassUtils.isAssignable(Boolean.class, Float.TYPE, true));
+        assertFalse("boolean -> double", ClassUtils.isAssignable(Boolean.class, Double.TYPE, true));
+        assertTrue("boolean -> boolean", ClassUtils.isAssignable(Boolean.class, Boolean.TYPE, true));
     }
     
     public void testPrimitiveToWrapper() {