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
This commit is contained in:
Robert Burrell Donkin 2002-11-20 21:45:47 +00:00
parent b991b3f973
commit 0cc87fe88d
4 changed files with 178 additions and 55 deletions

View File

@ -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;
}
/**
* <p>Determine whether a type can be used as a parameter in a method invocation.
* This method handles primitive conversions correctly.</p>
*
* <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
* a <code>Long</code> to a <code>long</code>,
* a <code>Float</code> to a <code>float</code>,
* a <code>Integer</code> to a <code>int</code>,
* and a <code>Double</code> to a <code>double</code>.
* Now logic widening matches are allowed.
* For example, a <code>Long</code> will not match a <code>int</code>.
*
* @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) {

View File

@ -69,7 +69,7 @@ import org.apache.commons.lang.StringUtils;
* reflection.
*
* @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
* @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 .
* <p>
* In other words, a <code>boolean</code> Class will be converted to
* a <code>Boolean</code> Class and so on.
* a <code>Boolean</code> Class and so on.</p>
*
* <p>This method also handles widening for primitives as given in section 5.1.2 of the
* <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>.
*
* @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;
}
/**
* <p>Determine whether a type can be used as a parameter in a method invocation.
* This method handles primitive conversions correctly.</p>
*
* <p>This method also handles widening for primitives as given in section 5.1.2 of the
* <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>.
*
* @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.

View File

@ -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;

View File

@ -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);
}
}