MethodInvoker.java
Upload User: jiancairen
Upload Date: 2007-08-27
Package Size: 26458k
Code Size: 7k
Category:

Java Develop

Development Platform:

Java

  1. /*
  2.  * Copyright 2002-2004 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.util;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.Modifier;
  20. /**
  21.  * Helper class that allows to specify a method to invoke in a
  22.  * declarative fashion, be it static or non-static.
  23.  *
  24.  * <p>Usage: Specify targetClass/targetMethod respectively
  25.  * targetObject/targetMethod, optionally specify arguments,
  26.  * prepare the invoker. Afterwards, you can invoke the method
  27.  * any number of times.
  28.  *
  29.  * <p>Typically not used directly but via its subclasses
  30.  * MethodInvokingFactoryBean and MethodInvokingJobDetailFactoryBean.
  31.  *
  32.  * @author Colin Sampaleanu
  33.  * @author Juergen Hoeller
  34.  * @since 19.02.2004
  35.  * @see #prepare
  36.  * @see #invoke
  37.  * @see org.springframework.beans.factory.config.MethodInvokingFactoryBean
  38.  * @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
  39.  */
  40. public class MethodInvoker {
  41. public static final VoidType VOID = new VoidType();
  42. private Class targetClass;
  43. private Object targetObject;
  44. private String targetMethod;
  45. private Object[] arguments;
  46. // the method we will call
  47. private Method methodObject;
  48. /**
  49.  * Set the target class on which to call the target method.
  50.  * Only necessary when the target method is static; else,
  51.  * a target object needs to be specified anyway.
  52.  * @see #setTargetObject
  53.  * @see #setTargetMethod
  54.  */
  55. public void setTargetClass(Class targetClass) {
  56. this.targetClass = targetClass;
  57. }
  58. /**
  59.  * Return the target class on which to call the target method.
  60.  */
  61. public Class getTargetClass() {
  62. return targetClass;
  63. }
  64. /**
  65.  * Set the target object on which to call the target method.
  66.  * Only necessary when the target method is not static;
  67.  * else, a target class is sufficient.
  68.  * @see #setTargetClass
  69.  * @see #setTargetMethod
  70.  */
  71. public void setTargetObject(Object targetObject) {
  72. this.targetObject = targetObject;
  73. }
  74. /**
  75.  * Return the target object on which to call the target method.
  76.  */
  77. public Object getTargetObject() {
  78. return targetObject;
  79. }
  80. /**
  81.  * Set the name of the method to be invoked.
  82.  * Refers to either a static method or a non-static method,
  83.  * depending on a target object being set.
  84.  * @see #setTargetClass
  85.  * @see #setTargetObject
  86.  */
  87. public void setTargetMethod(String targetMethod) {
  88. this.targetMethod = targetMethod;
  89. }
  90. /**
  91.  * Return the name of the method to be invoked.
  92.  */
  93. public String getTargetMethod() {
  94. return targetMethod;
  95. }
  96. /**
  97.  * Set a fully qualified static method name to invoke,
  98.  * e.g. "example.MyExampleClass.myExampleMethod".
  99.  * Convenient alternative to specifying targetClass and targetMethod.
  100.  * @see #setTargetClass
  101.  * @see #setTargetMethod
  102.  */
  103. public void setStaticMethod(String staticMethod) throws ClassNotFoundException {
  104. int lastDotIndex = staticMethod.lastIndexOf('.');
  105. if (lastDotIndex == -1 || lastDotIndex == staticMethod.length()) {
  106. throw new IllegalArgumentException("staticMethod must be a fully qualified class plus method name: " +
  107.  "e.g. 'example.MyExampleClass.myExampleMethod'");
  108. }
  109. String className = staticMethod.substring(0, lastDotIndex);
  110. String methodName = staticMethod.substring(lastDotIndex + 1);
  111. setTargetClass(Class.forName(className, true, Thread.currentThread().getContextClassLoader()));
  112. setTargetMethod(methodName);
  113. }
  114. /**
  115.  * Set arguments for the method invocation. If this property is not set,
  116.  * or the Object array is of length 0, a method with no arguments is assumed.
  117.  */
  118. public void setArguments(Object[] arguments) {
  119. this.arguments = arguments;
  120. }
  121. public Object[] getArguments() {
  122. return arguments;
  123. }
  124. /**
  125.  * Prepare the specified method.
  126.  * The method can be invoked any number of times afterwards.
  127.  * @see #getPreparedMethod
  128.  * @see #invoke
  129.  */
  130. public void prepare() throws ClassNotFoundException, NoSuchMethodException {
  131. if (this.targetClass == null && this.targetObject == null) {
  132. throw new IllegalArgumentException("Either targetClass or targetObject is required");
  133. }
  134. if (this.targetMethod == null) {
  135. throw new IllegalArgumentException("targetMethod is required");
  136. }
  137. if (this.arguments == null) {
  138. this.arguments = new Object[0];
  139. }
  140. Class[] types = new Class[this.arguments.length];
  141. for (int i = 0; i < this.arguments.length; ++i) {
  142. if (this.arguments[i] != null) {
  143. types[i] = this.arguments[i].getClass();
  144. }
  145. }
  146. // try to get the exact method first
  147. Class targetClass = (this.targetObject != null) ? this.targetObject.getClass() : this.targetClass;
  148. try {
  149. this.methodObject = targetClass.getMethod(this.targetMethod, types);
  150. }
  151. catch (NoSuchMethodException ex) {
  152. int matches = 0;
  153. // Then try to get a method with the same number of arguments.
  154. // We'll fail at runtime if in fact the arguments are not assignment compatible.
  155. Method[] methods = targetClass.getMethods();
  156. for (int i = 0; i < methods.length; ++i) {
  157. Method method = methods[i];
  158. if (method.getName().equals(this.targetMethod) && method.getParameterTypes().length == types.length) {
  159. this.methodObject = method;
  160. ++matches;
  161. }
  162. }
  163. // just rethrow exception if we can't get a match
  164. if (this.methodObject == null || matches > 1) {
  165. throw ex;
  166. }
  167. }
  168. if (this.targetObject == null && !Modifier.isStatic(this.methodObject.getModifiers())) {
  169. throw new IllegalArgumentException("Target method must not be non-static without a target");
  170. }
  171. }
  172. /**
  173.  * Return the prepared Method object that will be invoker.
  174.  * Can for example be used to determine the return type.
  175.  * @see #prepare
  176.  * @see #invoke
  177.  */
  178. public Method getPreparedMethod() {
  179. return this.methodObject;
  180. }
  181. /**
  182.  * Invoke the specified method.
  183.  * The invoker needs to have been prepared before.
  184.  * @return the object returned by the method invocation,
  185.  * or VOID if the method returns void
  186.  * @see #prepare
  187.  * @see #VOID
  188.  */
  189. public Object invoke() throws InvocationTargetException, IllegalAccessException {
  190. if (this.methodObject == null) {
  191. throw new IllegalStateException( "prepare() must be called prior to invoke() on MethodInvoker");
  192. }
  193. // in the static case, target will just be null
  194. Object result = this.methodObject.invoke(this.targetObject, this.arguments);
  195. return (result == null ? VOID : result);
  196. }
  197. /**
  198.  * Special marker class used for a void return value,
  199.  * differentiating void from a null value returned by the method.
  200.  */
  201. public static class VoidType {
  202. }
  203. }