@ -20,6 +20,7 @@ import java.io.PrintStream;
@@ -20,6 +20,7 @@ import java.io.PrintStream;
import java.util.ArrayList ;
import java.util.List ;
import org.springframework.expression.EvaluationException ;
import org.springframework.expression.ParseException ;
import org.springframework.expression.TypedValue ;
import org.springframework.expression.spel.ast.FormatHelper ;
@ -94,13 +95,6 @@ public class HelperTests extends ExpressionTestCase {
@@ -94,13 +95,6 @@ public class HelperTests extends ExpressionTestCase {
checkMatch ( new Class [ ] { String . class , Integer . class } , new Class [ ] { String . class , Integer . class } , typeConverter , ArgsMatchKind . EXACT ) ;
}
public void testReflectionHelperCompareArguments_Varargs_ExactMatching ( ) {
StandardTypeConverter tc = new StandardTypeConverter ( ) ;
// Calling foo(String) with (String) is exact match
checkMatch ( new Class [ ] { String . class } , new Class [ ] { String . class } , tc , ArgsMatchKind . EXACT ) ;
}
public void testReflectionHelperCompareArguments_CloseMatching ( ) {
StandardTypeConverter typeConverter = new StandardTypeConverter ( ) ;
@ -136,6 +130,131 @@ public class HelperTests extends ExpressionTestCase {
@@ -136,6 +130,131 @@ public class HelperTests extends ExpressionTestCase {
// Passing (Super,String) on call to foo(Sub,String) is not a match
checkMatch ( new Class [ ] { Super . class , String . class } , new Class [ ] { Sub . class , String . class } , typeConverter , null ) ;
}
public void testReflectionHelperCompareArguments_Varargs_ExactMatching ( ) {
StandardTypeConverter tc = new StandardTypeConverter ( ) ;
Class < ? > stringArrayClass = new String [ 0 ] . getClass ( ) ;
Class < ? > integerArrayClass = new Integer [ 0 ] . getClass ( ) ;
// Passing (String[]) on call to (String[]) is exact match
checkMatch2 ( new Class [ ] { stringArrayClass } , new Class [ ] { stringArrayClass } , tc , ArgsMatchKind . EXACT ) ;
// Passing (Integer, String[]) on call to (Integer, String[]) is exact match
checkMatch2 ( new Class [ ] { Integer . class , stringArrayClass } , new Class [ ] { Integer . class , stringArrayClass } , tc , ArgsMatchKind . EXACT ) ;
// Passing (String, Integer, String[]) on call to (String, String, String[]) is exact match
checkMatch2 ( new Class [ ] { String . class , Integer . class , stringArrayClass } , new Class [ ] { String . class , Integer . class , stringArrayClass } , tc , ArgsMatchKind . EXACT ) ;
// Passing (Sub, String[]) on call to (Super, String[]) is exact match
checkMatch2 ( new Class [ ] { Sub . class , stringArrayClass } , new Class [ ] { Super . class , stringArrayClass } , tc , ArgsMatchKind . CLOSE ) ;
// Passing (Integer, String[]) on call to (String, String[]) is exact match
checkMatch2 ( new Class [ ] { Integer . class , stringArrayClass } , new Class [ ] { String . class , stringArrayClass } , tc , ArgsMatchKind . REQUIRES_CONVERSION , 0 ) ;
// Passing (Integer, Sub, String[]) on call to (String, Super, String[]) is exact match
checkMatch2 ( new Class [ ] { Integer . class , Sub . class , String [ ] . class } , new Class [ ] { String . class , Super . class , String [ ] . class } , tc , ArgsMatchKind . REQUIRES_CONVERSION , 0 ) ;
// Passing (String) on call to (String[]) is exact match
checkMatch2 ( new Class [ ] { String . class } , new Class [ ] { stringArrayClass } , tc , ArgsMatchKind . EXACT ) ;
// Passing (Integer,String) on call to (Integer,String[]) is exact match
checkMatch2 ( new Class [ ] { Integer . class , String . class } , new Class [ ] { Integer . class , stringArrayClass } , tc , ArgsMatchKind . EXACT ) ;
// Passing (String) on call to (Integer[]) is conversion match (String to Integer)
checkMatch2 ( new Class [ ] { String . class } , new Class [ ] { integerArrayClass } , tc , ArgsMatchKind . REQUIRES_CONVERSION , 0 ) ;
// Passing (Sub) on call to (Super[]) is close match
checkMatch2 ( new Class [ ] { Sub . class } , new Class [ ] { new Super [ 0 ] . getClass ( ) } , tc , ArgsMatchKind . CLOSE ) ;
// Passing (Super) on call to (Sub[]) is not a match
checkMatch2 ( new Class [ ] { Super . class } , new Class [ ] { new Sub [ 0 ] . getClass ( ) } , tc , null ) ;
checkMatch2 ( new Class [ ] { Unconvertable . class , String . class } , new Class [ ] { Sub . class , Super [ ] . class } , tc , null ) ;
checkMatch2 ( new Class [ ] { Integer . class , Integer . class , String . class } , new Class [ ] { String . class , String . class , Super [ ] . class } , tc , null ) ;
checkMatch2 ( new Class [ ] { Unconvertable . class , String . class } , new Class [ ] { Sub . class , Super [ ] . class } , tc , null ) ;
checkMatch2 ( new Class [ ] { Integer . class , Integer . class , String . class } , new Class [ ] { String . class , String . class , Super [ ] . class } , tc , null ) ;
checkMatch2 ( new Class [ ] { Integer . class , Integer . class , Sub . class } , new Class [ ] { String . class , String . class , Super [ ] . class } , tc , ArgsMatchKind . REQUIRES_CONVERSION , 0 , 1 ) ;
checkMatch2 ( new Class [ ] { Integer . class , Integer . class , Integer . class } , new Class [ ] { Integer . class , String [ ] . class } , tc , ArgsMatchKind . REQUIRES_CONVERSION , 1 , 2 ) ;
// what happens on (Integer,String) passed to (Integer[]) ?
}
public void testConvertArguments ( ) throws Exception {
StandardTypeConverter tc = new StandardTypeConverter ( ) ;
// basic conversion int>String
Object [ ] args = new Object [ ] { 3 } ;
ReflectionHelper . convertArguments ( new Class [ ] { String . class } , false , tc , new int [ ] { 0 } , args ) ;
checkArguments ( args , "3" ) ;
// varargs but nothing to convert
args = new Object [ ] { 3 } ;
ReflectionHelper . convertArguments ( new Class [ ] { String . class , String [ ] . class } , false , tc , new int [ ] { 0 } , args ) ;
checkArguments ( args , "3" ) ;
// varargs with nothing needing conversion
args = new Object [ ] { 3 , "abc" , "abc" } ;
ReflectionHelper . convertArguments ( new Class [ ] { String . class , String [ ] . class } , true , tc , new int [ ] { 0 , 1 , 2 } , args ) ;
checkArguments ( args , "3" , "abc" , "abc" ) ;
// varargs with conversion required
args = new Object [ ] { 3 , false , 3 . 0d } ;
ReflectionHelper . convertArguments ( new Class [ ] { String . class , String [ ] . class } , true , tc , new int [ ] { 0 , 1 , 2 } , args ) ;
checkArguments ( args , "3" , "false" , "3.0" ) ;
}
public void testConvertArguments2 ( ) throws EvaluationException {
StandardTypeConverter tc = new StandardTypeConverter ( ) ;
// Simple conversion: int to string
Object [ ] args = new Object [ ] { 3 } ;
ReflectionHelper . convertAllArguments ( new Class [ ] { String . class } , false , tc , args ) ;
checkArguments ( args , "3" ) ;
// varargs conversion
args = new Object [ ] { 3 , false , 3 . 0f } ;
ReflectionHelper . convertAllArguments ( new Class [ ] { String . class , String [ ] . class } , true , tc , args ) ;
checkArguments ( args , "3" , "false" , "3.0" ) ;
// varargs conversion but no varargs
args = new Object [ ] { 3 } ;
ReflectionHelper . convertAllArguments ( new Class [ ] { String . class , String [ ] . class } , true , tc , args ) ;
checkArguments ( args , "3" ) ;
// missing converter
args = new Object [ ] { 3 , false , 3 . 0f } ;
try {
ReflectionHelper . convertAllArguments ( new Class [ ] { String . class , String [ ] . class } , true , null , args ) ;
fail ( "Should have failed because no converter supplied" ) ;
} catch ( SpelException se ) {
assertEquals ( SpelMessages . TYPE_CONVERSION_ERROR , se . getMessageUnformatted ( ) ) ;
}
// null value
args = new Object [ ] { 3 , null , 3 . 0f } ;
ReflectionHelper . convertAllArguments ( new Class [ ] { String . class , String [ ] . class } , true , tc , args ) ;
checkArguments ( args , "3" , null , "3.0" ) ;
}
public void testSetupArguments ( ) {
Object [ ] newArray = ReflectionHelper . setupArgumentsForVarargsInvocation ( new Class [ ] { new String [ 0 ] . getClass ( ) } , "a" , "b" , "c" ) ;
assertEquals ( 1 , newArray . length ) ;
Object firstParam = newArray [ 0 ] ;
assertEquals ( String . class , firstParam . getClass ( ) . getComponentType ( ) ) ;
Object [ ] firstParamArray = ( Object [ ] ) firstParam ;
assertEquals ( 3 , firstParamArray . length ) ;
assertEquals ( "a" , firstParamArray [ 0 ] ) ;
assertEquals ( "b" , firstParamArray [ 1 ] ) ;
assertEquals ( "c" , firstParamArray [ 2 ] ) ;
}
// test classes
static class Super {
}
@ -143,6 +262,8 @@ public class HelperTests extends ExpressionTestCase {
@@ -143,6 +262,8 @@ public class HelperTests extends ExpressionTestCase {
static class Sub extends Super {
}
static class Unconvertable { }
// ---
/ * *
@ -173,4 +294,44 @@ public class HelperTests extends ExpressionTestCase {
@@ -173,4 +294,44 @@ public class HelperTests extends ExpressionTestCase {
}
}
}
/ * *
* Used to validate the match returned from a compareArguments call .
* /
private void checkMatch2 ( Class [ ] inputTypes , Class [ ] expectedTypes , StandardTypeConverter typeConverter , ArgsMatchKind expectedMatchKind , int . . . argsForConversion ) {
ReflectionHelper . ArgumentsMatchInfo matchInfo = ReflectionHelper . compareArgumentsVarargs ( expectedTypes , inputTypes , typeConverter ) ;
if ( expectedMatchKind = = null ) {
assertNull ( "Did not expect them to match in any way: " + matchInfo , matchInfo ) ;
} else {
assertNotNull ( "Should not be a null match" , matchInfo ) ;
}
if ( expectedMatchKind = = ArgsMatchKind . EXACT ) {
assertTrue ( matchInfo . isExactMatch ( ) ) ;
assertNull ( matchInfo . argsRequiringConversion ) ;
} else if ( expectedMatchKind = = ArgsMatchKind . CLOSE ) {
assertTrue ( matchInfo . isCloseMatch ( ) ) ;
assertNull ( matchInfo . argsRequiringConversion ) ;
} else if ( expectedMatchKind = = ArgsMatchKind . REQUIRES_CONVERSION ) {
assertTrue ( "expected to be a match requiring conversion, but was " + matchInfo , matchInfo . isMatchRequiringConversion ( ) ) ;
if ( argsForConversion = = null ) {
fail ( "there are arguments that need conversion" ) ;
}
assertEquals ( "The array of args that need conversion is different length to that expected" , argsForConversion . length , matchInfo . argsRequiringConversion . length ) ;
for ( int a = 0 ; a < argsForConversion . length ; a + + ) {
assertEquals ( argsForConversion [ a ] , matchInfo . argsRequiringConversion [ a ] ) ;
}
}
}
private void checkArguments ( Object [ ] args , Object . . . expected ) {
assertEquals ( expected . length , args . length ) ;
for ( int i = 0 ; i < expected . length ; i + + ) {
checkArgument ( expected [ i ] , args [ i ] ) ;
}
}
private void checkArgument ( Object expected , Object actual ) {
assertEquals ( expected , actual ) ;
}
}