View Javadoc

1   /*
2    *  Copyright 2002-2004 The Apache Software Foundation
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 net.sf.collections15.functors.transformer;
17  
18  import net.sf.collections15.Closure;
19  import net.sf.collections15.Factory;
20  import net.sf.collections15.Predicate;
21  import net.sf.collections15.Transformer;
22  import net.sf.collections15.functors.predicate.EqualPredicate;
23  
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  /***
28   * <code>TransformerUtils</code> provides reference implementations and
29   * utilities for the {@link Transformer} functor interface. The supplied
30   * <code>Transformer</code>s are: <ul> <li>Invoker - returns the result of a
31   * method call on the input object <li>Clone - returns a clone of the input
32   * object <li>Constant - always returns the same object <li>Closure - performs a
33   * Closure and returns the input object <li>Predicate - returns the result of
34   * the predicate as a Boolean <li>Factory - returns a new object from a factory
35   * <li>Chained - chains two or more transformers together <li>Switch - calls one
36   * transformer based on one or more predicates <li>SwitchMap - calls one
37   * transformer looked up from a Map <li>Instantiate - the Class input object is
38   * instantiated <li>Map - returns an object from a supplied Map <li>Null -
39   * always returns null <li>NOP - returns the input object, which should be
40   * immutable <li>Exception - always throws an exception <li>StringValue -
41   * returns a <code>java.lang.String</code> representation of the input object
42   * </ul> All the supplied <code>Transformer</code>s are Serializable.
43   *
44   * @author Stephen Colebourne
45   * @author James Carman
46   * @author Chris Lambrou (port to Java 5.0)
47   * @since Collections15 1.0
48   */
49  public class TransformerUtils
50  {
51  
52      /***
53       * Protected constructor prevents direct instantiation, but allows users to
54       * extend this library to provide their own augmented static library class.
55       */
56      protected TransformerUtils()
57      {
58      }
59  
60      /***
61       * Returns a <code>Transformer</code> that always throws an exception. This
62       * could be useful during testing as a placeholder.
63       *
64       * @return A <code>Transformer</code> that always throws an exception.
65       *
66       * @see ExceptionTransformer
67       */
68      public static <I, O> Transformer<I, O> exceptionTransformer()
69      {
70          return ExceptionTransformer.getInstance();
71      }
72  
73      /***
74       * Returns a <code>Transformer</code> that always returns
75       * <code>null</code>.
76       *
77       * @return A <code>Transformer</code> that always returns
78       *         <code>null</code>.
79       *
80       * @see ConstantTransformer
81       */
82      public static <I, O> Transformer<I, O> nullTransformer()
83      {
84          return ConstantTransformer.getInstance(null);
85      }
86  
87      /***
88       * Returns a <code>Transformer</code> that simply returns the input object.
89       * The input object should be immutable to maintain the contract of
90       * <code>Transformer</code> (although this is not checked).
91       *
92       * @return A <code>Transformer</code> that simply returns the input object.
93       *
94       * @see NOPTransformer
95       */
96      public static <T> Transformer<T, T> nopTransformer()
97      {
98          return NOPTransformer.getInstance();
99      }
100 
101     /***
102      * Returns a <code>Transformer</code> that returns a clone of the input
103      * object. The input object will be cloned using one of these techniques (in
104      * order): <ul> <li>public clone method</li> <li>public copy
105      * constructor</li> <li>serialization clone <ul>
106      *
107      * @return A <code>Transformer</code> that returns a clone of the input
108      *         object.
109      *
110      * @see CloneTransformer
111      */
112     public static <T> Transformer<T, T> cloneTransformer()
113     {
114         return CloneTransformer.getInstance();
115     }
116 
117     /***
118      * Returns a <code>Transformer</code> that returns the same object each time
119      * the transformer is used.
120      *
121      * @param constantToReturn The constant object to be returned by the
122      *                         <code>Transformer</code>'s <code>transform</code>
123      *                         method.
124      *
125      * @return A <code>Transformer</code> that returns the same object each time
126      *         the transformer is used.
127      *
128      * @see ConstantTransformer
129      */
130     public static <I, O> Transformer<I, O> constantTransformer(O constantToReturn)
131     {
132         return ConstantTransformer.getInstance(constantToReturn);
133     }
134 
135     /***
136      * Returns a <code>Transformer</code> that executes a <code>Closure</code>
137      * on the input, before returning it as output.
138      *
139      * @param closure The <code>Closure</code> to execute in the transform.
140      *
141      * @return A <code>Transformer</code> that executes a <code>Closure</code>
142      *         on the input, before returning it as output.
143      *
144      * @throws IllegalArgumentException Throws if the <code>Closure</code> is
145      *                                  <code>null</code>.
146      * @see ClosureTransformer
147      */
148     public static <T> Transformer<T, T> asTransformer(Closure<T> closure)
149     {
150         return ClosureTransformer.getInstance(closure);
151     }
152 
153     /***
154      * Returns a <code>Transformer</code> that evaluates a
155      * <code>Predicate</code> each time the <code>Transformer</code> is used,
156      * with the result of the <code>Predicate</code> returned as output.
157      *
158      * @param predicate The <code>Predicate</code> to execute in the transform.
159      *
160      * @return A <code>Transformer</code> that evaluates a <code>Predicate</code>
161      *         each time the <code>Transformer</code> is used, with the result
162      *         of the <code>Predicate</code> returned as output.
163      *
164      * @throws IllegalArgumentException Thrown if the <code>Predicate</code> is
165      *                                  <code>null</code>.
166      * @see PredicateTransformer
167      */
168     public static <T> Transformer<T, Boolean> asTransformer(Predicate<T> predicate)
169     {
170         return PredicateTransformer.getInstance(predicate);
171     }
172 
173     /***
174      * Returns a <code>Transformer</code> implementation whose
175      * <code>transform</code> method uses a {@link Factory} to create the
176      * returned output object.
177      *
178      * @param factory The <code>factory</codd> used to create the transform
179      *                output objects.
180      *
181      * @return A <code>Transformer</code> implementation whose
182      *         <code>transform</code> method uses a {@link Factory} to create
183      *         the returned output object.
184      *
185      * @throws IllegalArgumentException Thrown if the <code>Factory</code> is
186      *                                  <code>null</code>.
187      * @see FactoryTransformer
188      */
189     public static <I, O> Transformer<I, O> asTransformer(Factory<O> factory)
190     {
191         return FactoryTransformer.getInstance(factory);
192     }
193 
194     /***
195      * Returns a <code>Transformer</code> whose <code>transform</code> method
196      * chains together the <code>transform</code> methods of two existing
197      * <code>Transformer</code>s
198      * <p/>
199      * If you need to chain together more than two <code>Transformer</code>s,
200      * you can use {@link ChainedTransformer#getInstance} and the convenience
201      * methods {@link ChainedTransformer#append} and {@link
202      * ChainedTransformer#prepend} instead.
203      *
204      * @param transformer1 The first <code>Transformer</code>.
205      * @param transformer2 the second <code>Transformer</code>.
206      *
207      * @return A <code>Transformer</code> whose <code>transform</code> method
208      *         chains together the <code>transform</code> methods of two
209      *         existing <code>Transformer</code>s
210      *
211      * @throws IllegalArgumentException Thrown if either <code>Transformer</code>
212      *                                  is <code>null</code>.
213      * @see ChainedTransformer
214      */
215     public static <I, M, O> Transformer<I, O> chainedTransformer(Transformer<? super I, ? extends M> transformer1,
216                                                                  Transformer<? super M, ? extends O> transformer2)
217     {
218         return ChainedTransformer.getInstance(transformer1, transformer2);
219     }
220 
221     /***
222      * Returns a <code>Transformer</code> that delegates to one of two existing
223      * <code>Transformers</code>, depending on the result of a
224      * <code>Predicate</code>.
225      *
226      * @param predicate        The <code>Predicate</code> evaluated to determine
227      *                         which of the <code>Transformer</code>s to
228      *                         delegate to.
229      * @param trueTransformer  The <code>Transformer</code> used if the
230      *                         <code>Predicate</code> evaluates <code>true</code>.
231      * @param falseTransformer The <code>Transformer</code> used if the
232      *                         <code>Predicate</code> evaluates <code>false</code>.
233      *
234      * @return A <code>Transformer</code> that delegates to one of two existing
235      *         <code>Transformers</code>, depending on the result of a
236      *         <code>Predicate</code>.
237      *
238      * @throws IllegalArgumentException Thrown if any argument is <code>null</code>.
239      * @see SwitchTransformer
240      */
241     public static <I, O> Transformer<I, O> ifElseTransformer(Predicate<I> predicate, Transformer<I, O> trueTransformer, Transformer<I, O> falseTransformer)
242     {
243         Map<Predicate<I>, Transformer<I, O>> map = new HashMap<Predicate<I>, Transformer<I, O>>(3);
244         map.put(predicate, trueTransformer);
245         map.put(null, falseTransformer);
246         return SwitchTransformer.getInstance(map);
247     }
248 
249     /***
250      * Returns a <code>Transformer</code> instance that uses the specified map
251      * of <code>Predicates</code> and <code>Transformer</code>s, delegating to
252      * the <code>Transformer</code> whose corresponding <code>Predicate</code>
253      * evaluates to <code>true</code>.
254      *
255      * @param predicatesAndTransformers A map of <code>Predicate</code>s to
256      *                                  <code>Transformer</code>s. Each non-null
257      *                                  <code>Predicate</code> key defines a
258      *                                  single switch case, with the
259      *                                  corresponding <code>Transformer</code>
260      *                                  being used to transform an input object
261      *                                  if it matches the <code>Predicate</code>.
262      *                                  <p/>
263      *                                  <code>Predicate</code>s are evaluated in
264      *                                  the iteration order of the map's key
265      *                                  set, with the exception of the
266      *                                  <code>null Predicate</code> key. If a
267      *                                  <code>null Predicate</code> key is
268      *                                  specified in the set, it's corresponding
269      *                                  <code>Transformer</code> is treated as
270      *                                  the default case, used to transform an
271      *                                  input object if it doesn't satisfy any
272      *                                  of the non-<code>null Predicate</code>
273      *                                  cases. If there is no default
274      *                                  <code>Transformer</code>, an
275      *                                  <code>IllegalArgumentException</code>
276      *                                  will be thrown by the <code>transform</code>
277      *                                  method.
278      *                                  <p/>
279      *                                  <b>Note that the map is not modified by
280      *                                  this method</b>.
281      *
282      * @return A new instance that uses the specified map of
283      *         <code>Predicates</code> and <code>Transformer</code>s.
284      *
285      * @throws IllegalArgumentException Thrown if the map is <code>null</code>.
286      * @throws IllegalArgumentException Thrown if any <code>Transformer</code>
287      *                                  in the map is <code>null</code>.
288      */
289     public static <I, O> Transformer<I, O> switchTransformer(Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers)
290     {
291         return SwitchTransformer.getInstance(predicatesAndTransformers);
292     }
293 
294     /***
295      * Returns a <code>Transformer</code> that uses the input object as a key to
296      * find the <code>Transformer</code> to delegate to.
297      *
298      * @param objectsAndTransformers A map consisting of object keys and
299      *                               <code>Transformer</code> values. The map is
300      *                               used to obtain a <code>Transformer</code>
301      *                               for an input object, which is then used to
302      *                               tansform the input object. If there is no
303      *                               matching <code>Transformer</code>, the
304      *                               default <code>Transformer</code> is used
305      *                               instead (specified in the map using a
306      *                               <code>null</code> key). If there is no
307      *                               default <code>Transformer</code>, an
308      *                               <code>IllegalArgumentException</code> will
309      *                               be thrown by the <code>transform</code>
310      *                               method.
311      *
312      * @return A <code>Transformer</code> that uses the input object as a key to
313      *         find the <code>Transformer</code> to delegate to.
314      *
315      * @throws IllegalArgumentException Thrown if the map is <code>null</code>,
316      *                                  empty, or any <code>Transformer</code>
317      *                                  in the map is <code>null</code>.
318      * @see SwitchTransformer
319      */
320     public static <I, O> Transformer<I, O> switchMapTransformer(Map<I, Transformer<I, O>> objectsAndTransformers)
321     {
322         if (objectsAndTransformers == null) {
323             throw new IllegalArgumentException("The object and transformer map must not be null");
324         }
325         int size = (2 + (objectsAndTransformers.size() * 4)) / 3; //this calulation is due to HashMap's misleading definition of initial capacity
326         Map<Predicate<I>, Transformer<I, O>> map = new HashMap<Predicate<I>, Transformer<I, O>>(size);
327         for (Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
328             I key = entry.getKey();
329             Predicate<I> predicate = key == null ? null : EqualPredicate.getInstance(key);
330             map.put(predicate, entry.getValue());
331         }
332         return SwitchTransformer.getInstance(map);
333     }
334 
335     /***
336      * Returns a <code>Transformer</code> that takes an input <code>Class</code>
337      * object and uses it to output an instance of that class, created by
338      * reflection using the parameterless constructor of the
339      * <code>Class</code>.
340      *
341      * @return A <code>Transformer</code> that takes an input <code>Class</code>
342      *         object and uses it to output an instance of that class, created
343      *         by reflection using the parameterless constructor of the
344      *         <code>Class</code>.
345      *
346      * @see InstantiateTransformer
347      * @see InstantiateTransformer#transform
348      */
349     public static <T> Transformer<Class<? extends T>, T> instantiateTransformer()
350     {
351         return InstantiateTransformer.getInstance();
352     }
353 
354     /***
355      * Returns a <code>Transformer</code> that takes an input <code>Class</code>
356      * object and uses it to output an instance of that class, created by
357      * reflection using the constructor of the <code>Class</code> specified by
358      * the <code>parameterTypes</code> argument, passing in the corresponding
359      * <code>arguments</code> to the constructor.
360      *
361      * @param parameterTypes The parameter types of the constructer to invoke on
362      *                       an input <code>Class</code>. May be
363      *                       <code>null</code> or empty if <code>arguments</code>
364      *                       is also <code>null</code> or empty, in which case
365      *                       the parameterless constructor will be used to
366      *                       create an output object from an input
367      *                       <code>Class</code>. The contents of this array are
368      *                       defensively copied.
369      * @param arguments      The arguments to pass to the constructor invoked on
370      *                       an input <code>Class</code>.
371      *
372      * @return A <code>Transformer</code> that takes an input <code>Class</code>
373      *         object and uses it to output an instance of that class, created
374      *         by reflection using the constructor of the <code>Class</code>
375      *         specified by the <code>parameterTypes</code> argument, passing in
376      *         the corresponding <code>arguments</code> to the constructor.
377      *
378      * @throws IllegalArgumentException Thrown if either of <code>parameterTypes</code>
379      *                                  or <code>arguments</code> is
380      *                                  <code>null</code>, but the other is
381      *                                  not.
382      * @throws IllegalArgumentException Thrown if any element in <code>parameterTypes</code>
383      *                                  is <code>null</code>.
384      * @throws IllegalArgumentException Thrown if any none-<code>null</code>
385      *                                  element in <code>arguments</code> is not
386      *                                  an instance of its corresponding
387      *                                  <code>parameterTypes</code> class.
388      * @see InstantiateTransformer
389      * @see InstantiateTransformer#transform
390      */
391     public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(Class[] parameterTypes, Object[] arguments)
392     {
393         return InstantiateTransformer.getInstance(parameterTypes, arguments);
394     }
395 
396     /***
397      * Returns a <code>Transformer</code> that uses the specified map as a
398      * lookup to transform the input objects into the output objects.
399      *
400      * @param map The map used as a lookup to transform the input objects into
401      *            output objects.
402      *
403      * @return A <code>Transformer</code> that uses the specified map as a
404      *         lookup to transform the input objects into the output objects.
405      *
406      * @throws IllegalArgumentException if the map is <code>null</code>.
407      * @see MapTransformer
408      */
409     public static <I, O> Transformer<I, O> mapTransformer(Map<? extends I, ? extends O> map)
410     {
411         return MapTransformer.getInstance(map);
412     }
413 
414     /***
415      * Returns a <code>Transformer</code> that invokes a specified method on the
416      * input object. The method must have no parameters.
417      * <p/>
418      * For example, <code>TransformerUtils.invokerTransformer("getName");</code>
419      * will call the <code>getName/code> method on the input object and output
420      * the return value.
421      * <p/>
422      * If a <code>null Class</code> is input to the <code>Transformer</code> it
423      * will throw an <code>IllegalArgumentException</code>.
424      *
425      * @param methodName the method name to call on the input object, may not be
426      *                   null. The return type of the method must be assignable
427      *                   to the generic type <code>&lt;O&gt;</code>
428      *
429      * @return A<code>Transformer</code> that invokes a specified method on the
430      *         input object. The method must have no parameters.
431      *
432      * @throws IllegalArgumentException if <code>methodName</code> is null.
433      * @see InvokerTransformer
434      * @see InvokerTransformer#transform
435      */
436     public static <I, O> Transformer<I, O> invokerTransformer(String methodName)
437     {
438         return InvokerTransformer.getInstance(methodName, null, null);
439     }
440 
441     /***
442      * Returns a <code>Transformer</code> that invokes a specified method on the
443      * input object.
444      *
445      * @param methodName     the method name to call on the input object, may
446      *                       not be null. The return type of the method must be
447      *                       assignable to the generic type <code>&lt;O&gt;</code>
448      * @param parameterTypes The parameter types of the method to invoke on an
449      *                       input object. May be <code>null</code> or empty if
450      *                       <code>arguments</code> is also <code>null</code> or
451      *                       empty, in which case the parameterless mehod of the
452      *                       specified name will be used. The contents of this
453      *                       array are defensively copied.
454      * @param arguments      The arguments to pass to the method invoked on an
455      *                       input <code>Class</code>.
456      *
457      * @return A <code>Transformer</code> that invokes a specified method on the
458      *         input object.
459      *
460      * @throws IllegalArgumentException Thrown if the method name argument is
461      *                                  <code>null</code>.
462      * @throws IllegalArgumentException Thrown if either of <code>parameterTypes</code>
463      *                                  or <code>arguments</code> is
464      *                                  <code>null</code>, but the other is
465      *                                  not.
466      * @throws IllegalArgumentException Thrown if any element in <code>parameterTypes</code>
467      *                                  is <code>null</code>.
468      * @throws IllegalArgumentException Thrown if any none-<code>null</code>
469      *                                  element in <code>arguments</code> is not
470      *                                  an instance of its corresponding
471      *                                  <code>parameterTypes</code> class.
472      * @see InvokerTransformer
473      * @see InvokerTransformer#transform
474      */
475     public static <I, O> Transformer<I, O> invokerTransformer(String methodName, Class[] parameterTypes, Object[] arguments)
476     {
477         return InvokerTransformer.getInstance(methodName, parameterTypes, arguments);
478     }
479 
480     /***
481      * Returns a <code>Transformer</code> that outputs the string value of the
482      * input, using the <code>String.valueOf</code> method. <code>null</code>
483      * returns 'null'.
484      *
485      * @return A <code>Transformer</code> that outputs the string value of the
486      *         input, using the <code>String.valueOf</code> method.
487      *
488      * @see StringValueTransformer
489      */
490     public static <E> Transformer<E, String> stringValueTransformer()
491     {
492         return StringValueTransformer.getInstance();
493     }
494 
495 }