View Javadoc

1   /*
2    * Copyright 2002-2008 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  
17  /*
18   * Copyright 2002-2008 the original author or authors.
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.springframework.batch.support;
33  
34  import java.lang.reflect.Method;
35  import java.util.Arrays;
36  
37  import org.springframework.aop.framework.Advised;
38  import org.springframework.util.Assert;
39  import org.springframework.util.ClassUtils;
40  
41  /**
42   * Simple implementation of the {@link MethodInvoker} interface that invokes a
43   * method on an object. If the method has no arguments, but arguments are
44   * provided, they are ignored and the method is invoked anyway. If there are
45   * more arguments than there are provided, then an exception is thrown.
46   * 
47   * @author Lucas Ward
48   * @since 2.0
49   */
50  public class SimpleMethodInvoker implements MethodInvoker {
51  
52  	private final Object object;
53  
54  	private Method method;
55  
56  	public SimpleMethodInvoker(Object object, Method method) {
57  		Assert.notNull(object, "Object to invoke must not be null");
58  		Assert.notNull(method, "Method to invoke must not be null");
59  		this.method = method;
60  		this.object = object;
61  	}
62  
63  	public SimpleMethodInvoker(Object object, String methodName, Class<?>... paramTypes) {
64  		Assert.notNull(object, "Object to invoke must not be null");
65  		this.method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, paramTypes);
66  		if (this.method == null) {
67  			// try with no params
68  			this.method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, new Class[] {});
69  		}
70  		if (this.method == null) {
71  			throw new IllegalArgumentException("No methods found for name: [" + methodName + "] in class: ["
72  					+ object.getClass() + "] with arguments of type: [" + Arrays.toString(paramTypes) + "]");
73  		}
74  		this.object = object;
75  	}
76  
77  	/*
78  	 * (non-Javadoc)
79  	 * 
80  	 * @see
81  	 * org.springframework.batch.core.configuration.util.MethodInvoker#invokeMethod
82  	 * (java.lang.Object[])
83  	 */
84      @Override
85  	public Object invokeMethod(Object... args) {
86  
87  		Class<?>[] parameterTypes = method.getParameterTypes();
88  		Object[] invokeArgs;
89  		if (parameterTypes.length == 0) {
90  			invokeArgs = new Object[] {};
91  		}
92  		else if (parameterTypes.length != args.length) {
93  			throw new IllegalArgumentException("Wrong number of arguments, expected no more than: ["
94  					+ parameterTypes.length + "]");
95  		}
96  		else {
97  			invokeArgs = args;
98  		}
99  
100 		method.setAccessible(true);
101 
102 		try {
103 			// Extract the target from an Advised as late as possible
104 			// in case it contains a lazy initialization
105 			Object target = extractTarget(object, method);
106 			return method.invoke(target, invokeArgs);
107 		}
108 		catch (Exception e) {
109 			throw new IllegalArgumentException("Unable to invoke method: [" + method + "] on object: [" + object
110 					+ "] with arguments: [" + Arrays.toString(args) + "]", e);
111 		}
112 	}
113 
114 	private Object extractTarget(Object target, Method method) {
115 		if (target instanceof Advised) {
116 			Object source;
117 			try {
118 				source = ((Advised) target).getTargetSource().getTarget();
119 			}
120 			catch (Exception e) {
121 				throw new IllegalStateException("Could not extract target from proxy", e);
122 			}
123 			if (source instanceof Advised) {
124 				source = extractTarget(source, method);
125 			}
126 			if (method.getDeclaringClass().isAssignableFrom(source.getClass())) {
127 				target = source;
128 			}
129 		}
130 		return target;
131 	}
132 
133 	@Override
134 	public boolean equals(Object obj) {
135 		if (!(obj instanceof SimpleMethodInvoker)) {
136 			return false;
137 		}
138 
139 		if (obj == this) {
140 			return true;
141 		}
142 		SimpleMethodInvoker rhs = (SimpleMethodInvoker) obj;
143 		return (rhs.method.equals(this.method)) && (rhs.object.equals(this.object));
144 	}
145 
146 	@Override
147 	public int hashCode() {
148 		int result = 25;
149 		result = 31 * result + object.hashCode();
150 		result = 31 * result + method.hashCode();
151 		return result;
152 	}
153 }