001/* 002 * Copyright 2006-2010 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.springframework.batch.item.adapter; 017 018import java.lang.reflect.Method; 019 020import org.springframework.util.ClassUtils; 021import org.springframework.util.MethodInvoker; 022import org.springframework.util.ReflectionUtils; 023 024/** 025 * A {@link MethodInvoker} that is a bit relaxed about its arguments. You can 026 * give it arguments in the wrong order or you can give it too many arguments 027 * and it will try and find a method that matches a subset. 028 * 029 * @author Dave Syer 030 * 031 * @since 2.1 032 */ 033public class HippyMethodInvoker extends MethodInvoker { 034 035 @Override 036 protected Method findMatchingMethod() { 037 String targetMethod = getTargetMethod(); 038 Object[] arguments = getArguments(); 039 int argCount = arguments.length; 040 041 Method[] candidates = ReflectionUtils.getAllDeclaredMethods(getTargetClass()); 042 int minTypeDiffWeight = Integer.MAX_VALUE; 043 Method matchingMethod = null; 044 045 Object[] transformedArguments = null; 046 int transformedArgumentCount = 0; 047 048 for (int i = 0; i < candidates.length; i++) { 049 Method candidate = candidates[i]; 050 if (candidate.getName().equals(targetMethod)) { 051 Class<?>[] paramTypes = candidate.getParameterTypes(); 052 Object[] candidateArguments = new Object[paramTypes.length]; 053 int assignedParameterCount = 0; 054 boolean assigned = paramTypes.length==0; 055 for (int j = 0; j < arguments.length; j++) { 056 for (int k = 0; k < paramTypes.length; k++) { 057 // Pick the first assignable of the right type that 058 // matches this slot and hasn't already been filled... 059 if (ClassUtils.isAssignableValue(paramTypes[k], arguments[j]) && candidateArguments[k] == null) { 060 candidateArguments[k] = arguments[j]; 061 assignedParameterCount++; 062 assigned = true; 063 break; 064 } 065 } 066 } 067 if (assigned && paramTypes.length <= argCount) { 068 int typeDiffWeight = getTypeDifferenceWeight(paramTypes, candidateArguments); 069 if (typeDiffWeight < minTypeDiffWeight) { 070 minTypeDiffWeight = typeDiffWeight; 071 matchingMethod = candidate; 072 transformedArguments = candidateArguments; 073 transformedArgumentCount = assignedParameterCount; 074 } 075 } 076 } 077 } 078 079 if (transformedArguments == null) { 080 throw new IllegalArgumentException("No matching arguments found for method: " + targetMethod); 081 } 082 083 if (transformedArgumentCount < transformedArguments.length) { 084 throw new IllegalArgumentException("Only " + transformedArgumentCount + " out of " 085 + transformedArguments.length + " arguments could be assigned."); 086 } 087 088 setArguments(transformedArguments); 089 return matchingMethod; 090 091 } 092}