View Javadoc

1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.batch.item.adapter;
17  
18  import java.lang.reflect.Method;
19  
20  import org.springframework.util.ClassUtils;
21  import org.springframework.util.MethodInvoker;
22  import org.springframework.util.ReflectionUtils;
23  
24  /**
25   * A {@link MethodInvoker} that is a bit relaxed about its arguments. You can
26   * give it arguments in the wrong order or you can give it too many arguments
27   * and it will try and find a method that matches a subset.
28   * 
29   * @author Dave Syer
30   * 
31   * @since 2.1
32   */
33  public class HippyMethodInvoker extends MethodInvoker {
34  
35  	@Override
36  	protected Method findMatchingMethod() {
37  		String targetMethod = getTargetMethod();
38  		Object[] arguments = getArguments();
39  		int argCount = arguments.length;
40  
41  		Method[] candidates = ReflectionUtils.getAllDeclaredMethods(getTargetClass());
42  		int minTypeDiffWeight = Integer.MAX_VALUE;
43  		Method matchingMethod = null;
44  
45  		Object[] transformedArguments = null;
46  		int transformedArgumentCount = 0;
47  
48  		for (int i = 0; i < candidates.length; i++) {
49  			Method candidate = candidates[i];
50  			if (candidate.getName().equals(targetMethod)) {
51  				Class<?>[] paramTypes = candidate.getParameterTypes();
52  				Object[] candidateArguments = new Object[paramTypes.length];
53  				int assignedParameterCount = 0;
54  				boolean assigned = paramTypes.length==0;
55  				for (int j = 0; j < arguments.length; j++) {
56  					for (int k = 0; k < paramTypes.length; k++) {
57  						// Pick the first assignable of the right type that
58  						// matches this slot and hasn't already been filled...
59  						if (ClassUtils.isAssignableValue(paramTypes[k], arguments[j]) && candidateArguments[k] == null) {
60  							candidateArguments[k] = arguments[j];
61  							assignedParameterCount++;
62  							assigned = true;
63  							break;
64  						}
65  					}
66  				}
67  				if (assigned && paramTypes.length <= argCount) {
68  					int typeDiffWeight = getTypeDifferenceWeight(paramTypes, candidateArguments);
69  					if (typeDiffWeight < minTypeDiffWeight) {
70  						minTypeDiffWeight = typeDiffWeight;
71  						matchingMethod = candidate;
72  						transformedArguments = candidateArguments;
73  						transformedArgumentCount = assignedParameterCount;
74  					}
75  				}
76  			}
77  		}
78  
79  		if (transformedArguments == null) {
80  			throw new IllegalArgumentException("No matching arguments found for method: " + targetMethod);
81  		}
82  
83  		if (transformedArgumentCount < transformedArguments.length) {
84  			throw new IllegalArgumentException("Only " + transformedArgumentCount + " out of "
85  					+ transformedArguments.length + " arguments could be assigned.");
86  		}
87  
88  		setArguments(transformedArguments);
89  		return matchingMethod;
90  
91  	}
92  }