From 0cc87fe88dd6ff6b82fd801be774ff20f2fe764e Mon Sep 17 00:00:00 2001 From: Robert Burrell Donkin Date: Wed, 20 Nov 2002 21:45:47 +0000 Subject: [PATCH] Moved isAssignmentCompatable method from MethodUtils into ReflectionUtils and renamed it. Enhanced existing isCompatible so that widening of primitives is allowed. Created test case for moved method. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137139 13f79535-47bb-0310-9956-ffa450edef68 --- .../commons/lang/reflect/MethodUtils.java | 55 +----------- .../commons/lang/reflect/ReflectionUtils.java | 86 ++++++++++++++++++- .../commons/lang/reflect/PrimitiveBean.java | 9 ++ .../lang/reflect/ReflectionUtilsTestCase.java | 83 ++++++++++++++++++ 4 files changed, 178 insertions(+), 55 deletions(-) diff --git a/src/java/org/apache/commons/lang/reflect/MethodUtils.java b/src/java/org/apache/commons/lang/reflect/MethodUtils.java index a4e3c3bfa..cc0c9cb63 100644 --- a/src/java/org/apache/commons/lang/reflect/MethodUtils.java +++ b/src/java/org/apache/commons/lang/reflect/MethodUtils.java @@ -82,7 +82,7 @@ import org.apache.commons.lang.StringUtils; * @author Gregor Raýman * @author Jan Sorensen * @author Robert Burrell Donkin - * @version $Id: MethodUtils.java,v 1.4 2002/11/18 23:00:26 rdonkin Exp $ + * @version $Id: MethodUtils.java,v 1.5 2002/11/20 21:45:47 rdonkin Exp $ */ public class MethodUtils { @@ -570,7 +570,7 @@ public class MethodUtils { log("Param=" + parameterTypes[n].getName()); log("Method=" + methodsParams[n].getName()); } - if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) { + if (!ReflectionUtils.isCompatable(parameterTypes[n], methodsParams[n])) { if (debug) { log(methodsParams[n] + " is not assignable from " + parameterTypes[n]); @@ -613,56 +613,7 @@ public class MethodUtils { // didn't find a match log("No match found."); return null; - } - - - /** - *

Determine whether a type can be used as a parameter in a method invocation. - * This method handles primitive conversions correctly.

- * - *

In order words, it will match a Boolean to a boolean, - * a Long to a long, - * a Float to a float, - * a Integer to a int, - * and a Double to a double. - * Now logic widening matches are allowed. - * For example, a Long will not match a int. - * - * @param parameterType the type of parameter accepted by the method - * @param parameterization the type of parameter being tested - * - * @return true if the assignement is compatible. - */ - private static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) { - // try plain assignment - if (parameterType.isAssignableFrom(parameterization)) { - return true; - } - - if (parameterType.isPrimitive()) { - // does anyone know a better strategy than comparing names? - // also, this method does *not* do widening - you must specify exactly - // is this the right behaviour? - if (boolean.class.equals(parameterType)) { - return Boolean.class.equals(parameterization); - } - if (float.class.equals(parameterType)) { - return Float.class.equals(parameterization); - } - if (long.class.equals(parameterType)) { - return Long.class.equals(parameterization); - } - if (int.class.equals(parameterType)) { - return Integer.class.equals(parameterization); - } - if (double.class.equals(parameterType)) { - return Double.class.equals(parameterization); - } - } - - return false; - } - + } private static void log(Object o) { if (debug) { diff --git a/src/java/org/apache/commons/lang/reflect/ReflectionUtils.java b/src/java/org/apache/commons/lang/reflect/ReflectionUtils.java index da51195bf..0d42989fe 100644 --- a/src/java/org/apache/commons/lang/reflect/ReflectionUtils.java +++ b/src/java/org/apache/commons/lang/reflect/ReflectionUtils.java @@ -69,7 +69,7 @@ import org.apache.commons.lang.StringUtils; * reflection. * * @author Stephen Colebourne - * @version $Id: ReflectionUtils.java,v 1.2 2002/11/18 23:01:36 rdonkin Exp $ + * @version $Id: ReflectionUtils.java,v 1.3 2002/11/20 21:45:47 rdonkin Exp $ */ public class ReflectionUtils { @@ -197,7 +197,10 @@ public class ReflectionUtils { * Primitive classes are handled correctly . *

* In other words, a boolean Class will be converted to - * a Boolean Class and so on. + * a Boolean Class and so on.

+ * + *

This method also handles widening for primitives as given in section 5.1.2 of the + * The Java Language Specification. * * @param requestedTypes the class array requested * @param paramTypes the actual class array for the method @@ -214,13 +217,90 @@ public class ReflectionUtils { paramTypes = ArrayUtils.EMPTY_CLASS_ARRAY; } for (int i = 0; i < requestedTypes.length; i++) { - if (ClassUtils.isAssignable(requestedTypes[i], paramTypes[i]) == false) { + if (isCompatable(requestedTypes[i], paramTypes[i]) == false) { return false; } } return true; } + + /** + *

Determine whether a type can be used as a parameter in a method invocation. + * This method handles primitive conversions correctly.

+ * + *

This method also handles widening for primitives as given in section 5.1.2 of the + * The Java Language Specification. + * + * @param parameterType the type of parameter accepted by the method + * @param requestedType the type of parameter being requested + * + * @return true if the assignement is compatible. + */ + public static boolean isCompatable(Class requestedType, Class parameterType) { + // try plain assignment + if (ClassUtils.isAssignable(requestedType, parameterType)) { + return true; + } + + if (parameterType.isPrimitive()) { + // also, this method does *not* do widening - you must specify exactly + // is this the right behaviour? + if (boolean.class.equals(parameterType)) { + return Boolean.class.equals(requestedType); + } + + if (byte.class.equals(parameterType)) { + return Byte.class.equals(requestedType); + } + + if (short.class.equals(parameterType)) { + return (Short.class.equals(requestedType) + || Byte.class.equals(requestedType)); + } + + if (char.class.equals(parameterType)) { + return Character.class.equals(requestedType); + } + + if (int.class.equals(parameterType)) { + return (Integer.class.equals(requestedType) + || Character.class.equals(requestedType) + || Short.class.equals(requestedType) + || Byte.class.equals(requestedType)); + } + if (long.class.equals(parameterType)) { + return (Long.class.equals(requestedType) + || Integer.class.equals(requestedType) + || Character.class.equals(requestedType) + || Short.class.equals(requestedType) + || Byte.class.equals(requestedType)); + } + + if (float.class.equals(parameterType)) { + return (Float.class.equals(requestedType) + || Long.class.equals(requestedType) + || Integer.class.equals(requestedType) + || Character.class.equals(requestedType) + || Short.class.equals(requestedType) + || Byte.class.equals(requestedType)); + } + + if (double.class.equals(parameterType)) { + return (Double.class.equals(requestedType) + || Float.class.equals(requestedType) + || Long.class.equals(requestedType) + || Integer.class.equals(requestedType) + || Character.class.equals(requestedType) + || Short.class.equals(requestedType) + || Byte.class.equals(requestedType)); + } + } + + return false; + } + + /** * Converts a primitive class to its matching object class. * Non-primitive classes are unaffected. diff --git a/src/test/org/apache/commons/lang/reflect/PrimitiveBean.java b/src/test/org/apache/commons/lang/reflect/PrimitiveBean.java index 2fb3d9ca5..3c2bcf1d1 100644 --- a/src/test/org/apache/commons/lang/reflect/PrimitiveBean.java +++ b/src/test/org/apache/commons/lang/reflect/PrimitiveBean.java @@ -67,6 +67,15 @@ public class PrimitiveBean { private boolean _boolean; private long _long; private int _int; + private short _short; + + public short getShort() { + return _short; + } + + public void setShort(short _short) { + this._short = _short; + } public float getFloat() { return _float; diff --git a/src/test/org/apache/commons/lang/reflect/ReflectionUtilsTestCase.java b/src/test/org/apache/commons/lang/reflect/ReflectionUtilsTestCase.java index c6f324d8b..8372b32ac 100644 --- a/src/test/org/apache/commons/lang/reflect/ReflectionUtilsTestCase.java +++ b/src/test/org/apache/commons/lang/reflect/ReflectionUtilsTestCase.java @@ -202,4 +202,87 @@ public class ReflectionUtilsTestCase extends TestCase { assertEquals("Static scope (method) [isPublicScope]", true, ReflectionUtils.isPublicScope(method)); assertEquals("Static scope (method) [isStatic]", true, ReflectionUtils.isStatic(method)); } + + public void testWidening() throws Exception + { + // test byte conversions + assertEquals("byte -> char", ReflectionUtils.isCompatable(Byte.class, char.class), false); + assertEquals("byte -> byte", ReflectionUtils.isCompatable(Byte.class, byte.class), true); + assertEquals("byte -> short", ReflectionUtils.isCompatable(Byte.class, short.class), true); + assertEquals("byte -> int", ReflectionUtils.isCompatable(Byte.class, int.class), true); + assertEquals("byte -> long", ReflectionUtils.isCompatable(Byte.class, long.class), true); + assertEquals("byte -> float", ReflectionUtils.isCompatable(Byte.class, float.class), true); + assertEquals("byte -> double", ReflectionUtils.isCompatable(Byte.class, double.class), true); + assertEquals("byte -> boolean", ReflectionUtils.isCompatable(Byte.class, boolean.class), false); + + // test short conversions + assertEquals("short -> char", ReflectionUtils.isCompatable(Short.class, char.class), false); + assertEquals("short -> byte", ReflectionUtils.isCompatable(Short.class, byte.class), false); + assertEquals("short -> short", ReflectionUtils.isCompatable(Short.class, short.class), true); + assertEquals("short -> int", ReflectionUtils.isCompatable(Short.class, int.class), true); + assertEquals("short -> long", ReflectionUtils.isCompatable(Short.class, long.class), true); + assertEquals("short -> float", ReflectionUtils.isCompatable(Short.class, float.class), true); + assertEquals("short -> double", ReflectionUtils.isCompatable(Short.class, double.class), true); + assertEquals("short -> boolean", ReflectionUtils.isCompatable(Short.class, boolean.class), false); + + // test char conversions + assertEquals("char -> char", ReflectionUtils.isCompatable(Character.class, char.class), true); + assertEquals("char -> byte", ReflectionUtils.isCompatable(Character.class, byte.class), false); + assertEquals("char -> short", ReflectionUtils.isCompatable(Character.class, short.class), false); + assertEquals("char -> int", ReflectionUtils.isCompatable(Character.class, int.class), true); + assertEquals("char -> long", ReflectionUtils.isCompatable(Character.class, long.class), true); + assertEquals("char -> float", ReflectionUtils.isCompatable(Character.class, float.class), true); + assertEquals("char -> double", ReflectionUtils.isCompatable(Character.class, double.class), true); + assertEquals("char -> boolean", ReflectionUtils.isCompatable(Character.class, boolean.class), false); + + // test int conversions + assertEquals("int -> char", ReflectionUtils.isCompatable(Integer.class, char.class), false); + assertEquals("int -> byte", ReflectionUtils.isCompatable(Integer.class, byte.class), false); + assertEquals("int -> short", ReflectionUtils.isCompatable(Integer.class, short.class), false); + assertEquals("int -> int", ReflectionUtils.isCompatable(Integer.class, int.class), true); + assertEquals("int -> long", ReflectionUtils.isCompatable(Integer.class, long.class), true); + assertEquals("int -> float", ReflectionUtils.isCompatable(Integer.class, float.class), true); + assertEquals("int -> double", ReflectionUtils.isCompatable(Integer.class, double.class), true); + assertEquals("int -> boolean", ReflectionUtils.isCompatable(Integer.class, boolean.class), false); + + // test long conversions + assertEquals("long -> char", ReflectionUtils.isCompatable(Long.class, char.class), false); + assertEquals("long -> byte", ReflectionUtils.isCompatable(Long.class, byte.class), false); + assertEquals("long -> short", ReflectionUtils.isCompatable(Long.class, short.class), false); + assertEquals("long -> int", ReflectionUtils.isCompatable(Long.class, int.class), false); + assertEquals("long -> long", ReflectionUtils.isCompatable(Long.class, long.class), true); + assertEquals("long -> float", ReflectionUtils.isCompatable(Long.class, float.class), true); + assertEquals("long -> double", ReflectionUtils.isCompatable(Long.class, double.class), true); + assertEquals("long -> boolean", ReflectionUtils.isCompatable(Long.class, boolean.class), false); + + // test float conversions + assertEquals("float -> char", ReflectionUtils.isCompatable(Float.class, char.class), false); + assertEquals("float -> byte", ReflectionUtils.isCompatable(Float.class, byte.class), false); + assertEquals("float -> short", ReflectionUtils.isCompatable(Float.class, short.class), false); + assertEquals("float -> int", ReflectionUtils.isCompatable(Float.class, int.class), false); + assertEquals("float -> long", ReflectionUtils.isCompatable(Float.class, long.class), false); + assertEquals("float -> float", ReflectionUtils.isCompatable(Float.class, float.class), true); + assertEquals("float -> double", ReflectionUtils.isCompatable(Float.class, double.class), true); + assertEquals("float -> boolean", ReflectionUtils.isCompatable(Float.class, boolean.class), false); + + // test float conversions + assertEquals("double -> char", ReflectionUtils.isCompatable(Double.class, char.class), false); + assertEquals("double -> byte", ReflectionUtils.isCompatable(Double.class, byte.class), false); + assertEquals("double -> short", ReflectionUtils.isCompatable(Double.class, short.class), false); + assertEquals("double -> int", ReflectionUtils.isCompatable(Double.class, int.class), false); + assertEquals("double -> long", ReflectionUtils.isCompatable(Double.class, long.class), false); + assertEquals("double -> float", ReflectionUtils.isCompatable(Double.class, float.class), false); + assertEquals("double -> double", ReflectionUtils.isCompatable(Double.class, double.class), true); + assertEquals("double -> boolean", ReflectionUtils.isCompatable(Double.class, boolean.class), false); + + // test float conversions + assertEquals("boolean -> char", ReflectionUtils.isCompatable(Boolean.class, char.class), false); + assertEquals("boolean -> byte", ReflectionUtils.isCompatable(Boolean.class, byte.class), false); + assertEquals("boolean -> short", ReflectionUtils.isCompatable(Boolean.class, short.class), false); + assertEquals("boolean -> int", ReflectionUtils.isCompatable(Boolean.class, int.class), false); + assertEquals("boolean -> long", ReflectionUtils.isCompatable(Boolean.class, long.class), false); + assertEquals("boolean -> float", ReflectionUtils.isCompatable(Boolean.class, float.class), false); + assertEquals("boolean -> double", ReflectionUtils.isCompatable(Boolean.class, double.class), false); + assertEquals("boolean -> boolean", ReflectionUtils.isCompatable(Boolean.class, boolean.class), true); + } }