|
49 | 49 | having to catch the exceptions. Method lookups are now cached at a high |
50 | 50 | level so they are less important, however the logic is messy. |
51 | 51 | */ |
52 | | -class Reflect |
53 | | -{ |
| 52 | +final class Reflect { |
| 53 | + |
54 | 54 | /** |
55 | 55 | Invoke method on arbitrary object instance. |
56 | 56 | invocation may be static (through the object instance) or dynamic. |
@@ -113,13 +113,31 @@ static Object invokeMethod( |
113 | 113 |
|
114 | 114 | logInvokeMethod( "Invoking method (entry): ", method, args ); |
115 | 115 |
|
| 116 | + boolean isVarArgs = method.isVarArgs(); |
| 117 | + |
116 | 118 | // Map types to assignable forms, need to keep this fast... |
117 | | - Object [] tmpArgs = new Object [ args.length ]; |
118 | 119 | Class [] types = method.getParameterTypes(); |
| 120 | + Object [] tmpArgs = new Object [ types.length ]; |
| 121 | + int fixedArgLen = types.length; |
| 122 | + if( isVarArgs ) { |
| 123 | + if( fixedArgLen==args.length && types[fixedArgLen-1].isAssignableFrom(args[fixedArgLen-1].getClass()) ) { |
| 124 | + isVarArgs = false; |
| 125 | + } else { |
| 126 | + fixedArgLen--; |
| 127 | + } |
| 128 | + } |
119 | 129 | try { |
120 | | - for (int i=0; i<args.length; i++) |
| 130 | + for (int i=0; i<fixedArgLen; i++) |
121 | 131 | tmpArgs[i] = Types.castObject( |
122 | 132 | args[i]/*rhs*/, types[i]/*lhsType*/, Types.ASSIGNMENT ); |
| 133 | + if( isVarArgs ) { |
| 134 | + Class varType = types[fixedArgLen].getComponentType(); |
| 135 | + Object varArgs = Array.newInstance( varType, args.length - fixedArgLen ); |
| 136 | + for( int i=fixedArgLen, j=0; i<args.length; i++, j++ ) |
| 137 | + Array.set( varArgs,j, Primitive.unwrap( Types.castObject( |
| 138 | + args[i]/*rhs*/, varType/*lhsType*/, Types.ASSIGNMENT ) ) ); |
| 139 | + tmpArgs[fixedArgLen] = varArgs; |
| 140 | + } |
123 | 141 | } catch ( UtilEvalError e ) { |
124 | 142 | throw new InterpreterError( |
125 | 143 | "illegal argument type in method invocation: "+e ); |
@@ -542,7 +560,8 @@ private static void gatherMethodsRecursive( |
542 | 560 | baseClass.getMethods() : baseClass.getDeclaredMethods(); |
543 | 561 | for( Method m : methods ) { |
544 | 562 | if ( m.getName().equals( methodName ) |
545 | | - && ( m.getParameterTypes().length == numArgs ) |
| 563 | + && ( m.isVarArgs() ? m.getParameterTypes().length-1 <= numArgs |
| 564 | + : m.getParameterTypes().length == numArgs ) |
546 | 565 | ) { |
547 | 566 | if( isPublicClass && isPublic(m) ) { |
548 | 567 | publicMethods.add( m ); |
@@ -653,12 +672,29 @@ private static Method findMostSpecificMethod( |
653 | 672 | Class[] idealMatch, List<Method> methods ) |
654 | 673 | { |
655 | 674 | // copy signatures into array for findMostSpecificMethod() |
656 | | - Class [][] candidateSigs = new Class [ methods.size() ][]; |
657 | | - for(int i=0; i<candidateSigs.length; i++) |
658 | | - candidateSigs[i] = methods.get(i).getParameterTypes(); |
| 675 | + List<Class[]> candidateSigs = new ArrayList<Class[]>(); |
| 676 | + List<Method> methodList = new ArrayList<Method>(); |
| 677 | + for( Method method : methods ) { |
| 678 | + Class[] parameterTypes = method.getParameterTypes(); |
| 679 | + methodList.add( method ); |
| 680 | + candidateSigs.add( parameterTypes ); |
| 681 | + if( method.isVarArgs() ) { |
| 682 | + Class[] candidateSig = new Class[idealMatch.length]; |
| 683 | + int j = 0; |
| 684 | + for( ; j<parameterTypes.length-1; j++ ) { |
| 685 | + candidateSig[j] = parameterTypes[j]; |
| 686 | + } |
| 687 | + Class varType = parameterTypes[j].getComponentType(); |
| 688 | + for( ; j<idealMatch.length; j++ ) { |
| 689 | + candidateSig[j] = varType; |
| 690 | + } |
| 691 | + methodList.add( method ); |
| 692 | + candidateSigs.add( candidateSig ); |
| 693 | + } |
| 694 | + } |
659 | 695 |
|
660 | | - int match = findMostSpecificSignature( idealMatch, candidateSigs ); |
661 | | - return match == -1 ? null : methods.get(match); |
| 696 | + int match = findMostSpecificSignature( idealMatch, candidateSigs.toArray(new Class[0][]) ); |
| 697 | + return match == -1 ? null : methodList.get(match); |
662 | 698 | } |
663 | 699 |
|
664 | 700 | /** |
|
0 commit comments