001: /*
002: * Copyright 2002-2007 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: * http://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: */
016:
017: package org.springframework.beans.support;
018:
019: import java.beans.PropertyEditor;
020: import java.lang.reflect.Method;
021:
022: import org.springframework.beans.PropertyEditorRegistry;
023: import org.springframework.beans.SimpleTypeConverter;
024: import org.springframework.beans.TypeConverter;
025: import org.springframework.beans.TypeMismatchException;
026: import org.springframework.util.ClassUtils;
027: import org.springframework.util.MethodInvoker;
028:
029: /**
030: * Subclass of MethodInvoker that tries to convert the given arguments
031: * for the actual target method via BeanWrapperImpl.
032: *
033: * <p>Supports flexible argument conversions, in particular for
034: * invoking a specific overloaded method.
035: *
036: * @author Juergen Hoeller
037: * @since 1.1
038: * @see org.springframework.beans.BeanWrapperImpl#convertIfNecessary
039: */
040: public class ArgumentConvertingMethodInvoker extends MethodInvoker {
041:
042: private TypeConverter typeConverter;
043:
044: private boolean useDefaultConverter = true;
045:
046: /**
047: * Set a TypeConverter to use for argument type conversion.
048: * <p>Default is a {@link org.springframework.beans.SimpleTypeConverter}.
049: * Can be overridden with any TypeConverter implementation, typically
050: * a pre-configured SimpleTypeConverter or a BeanWrapperImpl instance.
051: * @see org.springframework.beans.SimpleTypeConverter
052: * @see org.springframework.beans.BeanWrapperImpl
053: */
054: public void setTypeConverter(TypeConverter typeConverter) {
055: this .typeConverter = typeConverter;
056: this .useDefaultConverter = false;
057: }
058:
059: /**
060: * Return the TypeConverter used for argument type conversion.
061: * <p>Can be cast to {@link org.springframework.beans.PropertyEditorRegistry}
062: * if direct access to the underlying PropertyEditors is desired
063: * (provided that the present TypeConverter actually implements the
064: * PropertyEditorRegistry interface).
065: */
066: public TypeConverter getTypeConverter() {
067: if (this .typeConverter == null && this .useDefaultConverter) {
068: this .typeConverter = getDefaultTypeConverter();
069: }
070: return this .typeConverter;
071: }
072:
073: /**
074: * Obtain the default TypeConverter for this method invoker.
075: * <p>Called if no explicit TypeConverter has been specified.
076: * The default implementation builds a
077: * {@link org.springframework.beans.SimpleTypeConverter}.
078: * Can be overridden in subclasses.
079: */
080: protected TypeConverter getDefaultTypeConverter() {
081: return new SimpleTypeConverter();
082: }
083:
084: /**
085: * Register the given custom property editor for all properties of the given type.
086: * <p>Typically used in conjunction with the default
087: * {@link org.springframework.beans.SimpleTypeConverter}; will work with any
088: * TypeConverter that implements the PropertyEditorRegistry interface as well.
089: * @param requiredType type of the property
090: * @param propertyEditor editor to register
091: * @see #setTypeConverter
092: * @see org.springframework.beans.PropertyEditorRegistry#registerCustomEditor
093: */
094: public void registerCustomEditor(Class requiredType,
095: PropertyEditor propertyEditor) {
096: TypeConverter converter = getTypeConverter();
097: if (!(converter instanceof PropertyEditorRegistry)) {
098: throw new IllegalStateException(
099: "TypeConverter does not implement PropertyEditorRegistry interface: "
100: + converter);
101: }
102: ((PropertyEditorRegistry) converter).registerCustomEditor(
103: requiredType, propertyEditor);
104: }
105:
106: /**
107: * This implementation looks for a method with matching parameter types:
108: * that is, where each argument value is assignable to the corresponding parameter type.
109: */
110: protected Method findMatchingMethod() {
111: Method[] candidates = getTargetClass().getMethods();
112: Object[] arguments = getArguments();
113: int argCount = arguments.length;
114:
115: // First pass: look for method with directly assignable arguments.
116: for (int i = 0; i < candidates.length; i++) {
117: if (candidates[i].getName().equals(getTargetMethod())) {
118: // Check if the inspected method has the correct number of parameters.
119: Class[] paramTypes = candidates[i].getParameterTypes();
120: if (paramTypes.length == argCount) {
121: int numberOfCorrectArguments = 0;
122: for (int j = 0; j < argCount; j++) {
123: // Verify that the supplied argument is assignable to the method parameter.
124: if (ClassUtils.isAssignableValue(paramTypes[j],
125: arguments[j])) {
126: numberOfCorrectArguments++;
127: }
128: }
129: if (numberOfCorrectArguments == argCount) {
130: return candidates[i];
131: }
132: }
133: }
134: }
135:
136: // Second pass: look for method where arguments can be converted to parameter types.
137: TypeConverter converter = getTypeConverter();
138: if (converter != null) {
139: for (int i = 0; i < candidates.length; i++) {
140: if (candidates[i].getName().equals(getTargetMethod())) {
141: // Check if the inspected method has the correct number of parameters.
142: Class[] paramTypes = candidates[i]
143: .getParameterTypes();
144: if (paramTypes.length == argCount) {
145: Object[] argumentsToUse = new Object[argCount];
146: int numberOfCorrectArguments = 0;
147: for (int j = 0; j < argCount; j++) {
148: // Verify that the supplied argument is assignable to the method parameter.
149: try {
150: argumentsToUse[j] = converter
151: .convertIfNecessary(
152: arguments[j],
153: paramTypes[j]);
154: numberOfCorrectArguments++;
155: } catch (TypeMismatchException ex) {
156: // Ignore -> simply doesn't match.
157: }
158: }
159: if (numberOfCorrectArguments == argumentsToUse.length) {
160: setArguments(argumentsToUse);
161: return candidates[i];
162: }
163: }
164: }
165: }
166: }
167:
168: return null;
169: }
170:
171: }
|