View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections.functors;
18  
19  import java.io.Serializable;
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  
23  import org.apache.commons.collections.FunctorException;
24  import org.apache.commons.collections.Transformer;
25  
26  /**
27   * Transformer implementation that creates a new object instance by reflection.
28   *
29   * @since 3.0
30   * @version $Id: InvokerTransformer.java 1435965 2013-01-20 21:13:18Z tn $
31   */
32  public class InvokerTransformer<I, O> implements Transformer<I, O>, Serializable {
33  
34      /** The serial version */
35      private static final long serialVersionUID = -8653385846894047688L;
36      
37      /** The method name to call */
38      private final String iMethodName;
39      /** The array of reflection parameter types */
40      private final Class<?>[] iParamTypes;
41      /** The array of reflection arguments */
42      private final Object[] iArgs;
43  
44      /**
45       * Gets an instance of this transformer calling a specific method with no arguments.
46       * 
47       * @param <I>  the input type
48       * @param <O>  the output type
49       * @param methodName  the method name to call
50       * @return an invoker transformer
51       * @since 3.1
52       */
53      public static <I, O> Transformer<I, O> invokerTransformer(final String methodName) {
54          if (methodName == null) {
55              throw new IllegalArgumentException("The method to invoke must not be null");
56          }
57          return new InvokerTransformer<I, O>(methodName);
58      }
59  
60      /**
61       * Gets an instance of this transformer calling a specific method with specific values.
62       *
63       * @param <I>  the input type
64       * @param <O>  the output type
65       * @param methodName  the method name to call
66       * @param paramTypes  the parameter types of the method
67       * @param args  the arguments to pass to the method
68       * @return an invoker transformer
69       */
70      public static <I, O> Transformer<I, O> invokerTransformer(final String methodName, Class<?>[] paramTypes,
71                                                                Object[] args) {
72          if (methodName == null) {
73              throw new IllegalArgumentException("The method to invoke must not be null");
74          }
75          if (((paramTypes == null) && (args != null))
76              || ((paramTypes != null) && (args == null))
77              || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
78              throw new IllegalArgumentException("The parameter types must match the arguments");
79          }
80          if (paramTypes == null || paramTypes.length == 0) {
81              return new InvokerTransformer<I, O>(methodName);
82          } else {
83              paramTypes = paramTypes.clone();
84              args = args.clone();
85              return new InvokerTransformer<I, O>(methodName, paramTypes, args);
86          }
87      }
88  
89      /**
90       * Constructor for no arg instance.
91       * 
92       * @param methodName  the method to call
93       */
94      private InvokerTransformer(final String methodName) {
95          super();
96          iMethodName = methodName;
97          iParamTypes = null;
98          iArgs = null;
99      }
100 
101     /**
102      * Constructor that performs no validation.
103      * Use <code>getInstance</code> if you want that.
104      * 
105      * @param methodName  the method to call
106      * @param paramTypes  the constructor parameter types, not cloned
107      * @param args  the constructor arguments, not cloned
108      */
109     public InvokerTransformer(final String methodName, final Class<?>[] paramTypes, final Object[] args) {
110         super();
111         iMethodName = methodName;
112         iParamTypes = paramTypes;
113         iArgs = args;
114     }
115 
116     /**
117      * Transforms the input to result by invoking a method on the input.
118      * 
119      * @param input  the input object to transform
120      * @return the transformed result, null if null input
121      */
122     @SuppressWarnings("unchecked")
123     public O transform(final Object input) {
124         if (input == null) {
125             return null;
126         }
127         try {
128             final Class<?> cls = input.getClass();
129             final Method method = cls.getMethod(iMethodName, iParamTypes);
130             return (O) method.invoke(input, iArgs);
131         } catch (final NoSuchMethodException ex) {
132             throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
133                                        input.getClass() + "' does not exist");
134         } catch (final IllegalAccessException ex) {
135             throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
136                                        input.getClass() + "' cannot be accessed");
137         } catch (final InvocationTargetException ex) {
138             throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
139                                        input.getClass() + "' threw an exception", ex);
140         }
141     }
142 
143 }