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.collections4;
18  
19  import java.util.Collection;
20  import java.util.Map;
21  import java.util.Objects;
22  
23  import org.apache.commons.collections4.functors.ChainedTransformer;
24  import org.apache.commons.collections4.functors.CloneTransformer;
25  import org.apache.commons.collections4.functors.ClosureTransformer;
26  import org.apache.commons.collections4.functors.ConstantTransformer;
27  import org.apache.commons.collections4.functors.EqualPredicate;
28  import org.apache.commons.collections4.functors.ExceptionTransformer;
29  import org.apache.commons.collections4.functors.FactoryTransformer;
30  import org.apache.commons.collections4.functors.IfTransformer;
31  import org.apache.commons.collections4.functors.InstantiateTransformer;
32  import org.apache.commons.collections4.functors.InvokerTransformer;
33  import org.apache.commons.collections4.functors.MapTransformer;
34  import org.apache.commons.collections4.functors.NOPTransformer;
35  import org.apache.commons.collections4.functors.PredicateTransformer;
36  import org.apache.commons.collections4.functors.StringValueTransformer;
37  import org.apache.commons.collections4.functors.SwitchTransformer;
38  
39  /**
40   * {@code TransformerUtils} provides reference implementations and
41   * utilities for the Transformer functor interface. The supplied transformers are:
42   * <ul>
43   * <li>Invoker - returns the result of a method call on the input object
44   * <li>Clone - returns a clone of the input object
45   * <li>Constant - always returns the same object
46   * <li>Closure - performs a Closure and returns the input object
47   * <li>Predicate - returns the result of the predicate as a Boolean
48   * <li>Factory - returns a new object from a factory
49   * <li>Chained - chains two or more transformers together
50   * <li>If - calls one transformer or another based on a predicate
51   * <li>Switch - calls one transformer based on one or more predicates
52   * <li>SwitchMap - calls one transformer looked up from a Map
53   * <li>Instantiate - the Class input object is instantiated
54   * <li>Map - returns an object from a supplied Map
55   * <li>Null - always returns null
56   * <li>NOP - returns the input object, which should be immutable
57   * <li>Exception - always throws an exception
58   * <li>StringValue - returns a {@link String} representation of the input object
59   * </ul>
60   * <p>
61   * Since v4.1 only transformers which are considered to be safe are
62   * Serializable. Transformers considered to be unsafe for serialization are:
63   * </p>
64   * <ul>
65   * <li>Invoker
66   * <li>Clone
67   * <li>Instantiate
68   * </ul>
69   *
70   * @since 3.0
71   */
72  public class TransformerUtils {
73  
74      /**
75       * Creates a Transformer that calls a Closure each time the transformer is used.
76       * The transformer returns the input object.
77       *
78       * @param <T>  the input/output type
79       * @param closure  the closure to run each time in the transformer, not null
80       * @return the transformer
81       * @throws NullPointerException if the closure is null
82       * @see ClosureTransformer
83       */
84      public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) {
85          return ClosureTransformer.closureTransformer(closure);
86      }
87  
88      /**
89       * Creates a Transformer that calls a Factory each time the transformer is used.
90       * The transformer will return the value returned by the factory.
91       *
92       * @param <I>  the input type
93       * @param <O>  the output type
94       * @param factory  the factory to run each time in the transformer, not null
95       * @return the transformer
96       * @throws NullPointerException if the factory is null
97       * @see FactoryTransformer
98       */
99      public static <I, O> Transformer<I, O> asTransformer(final Factory<? extends O> factory) {
100         return FactoryTransformer.factoryTransformer(factory);
101     }
102 
103     /**
104      * Creates a Transformer that calls a Predicate each time the transformer is used.
105      * The transformer will return either {@link Boolean#TRUE} or {@link Boolean#FALSE}.
106      *
107      * @param <T>  the input type
108      * @param predicate  the predicate to run each time in the transformer, not null
109      * @return the transformer
110      * @throws NullPointerException if the predicate is null
111      * @see PredicateTransformer
112      */
113     public static <T> Transformer<T, Boolean> asTransformer(final Predicate<? super T> predicate) {
114         return PredicateTransformer.predicateTransformer(predicate);
115     }
116 
117     /**
118      * Create a new Transformer that calls each transformer in turn, passing the
119      * result into the next transformer. The ordering is that of the iterator()
120      * method on the collection.
121      *
122      * @param <T>  the input/output type
123      * @param transformers  a collection of transformers to chain
124      * @return the transformer
125      * @throws NullPointerException if the transformers collection or any of the transformers is null
126      * @see ChainedTransformer
127      */
128     public static <T> Transformer<T, T> chainedTransformer(
129             final Collection<? extends Transformer<? super T, ? extends T>> transformers) {
130         return ChainedTransformer.chainedTransformer(transformers);
131     }
132 
133     /**
134      * Create a new Transformer that calls each transformer in turn, passing the
135      * result into the next transformer.
136      *
137      * @param <T>  the input/output type
138      * @param transformers  an array of transformers to chain
139      * @return the transformer
140      * @throws NullPointerException if the transformers array or any of the transformers is null
141      * @see ChainedTransformer
142      */
143     public static <T> Transformer<T, T> chainedTransformer(
144             final Transformer<? super T, ? extends T>... transformers) {
145         return ChainedTransformer.chainedTransformer(transformers);
146     }
147 
148     /**
149      * Gets a transformer that returns a clone of the input object.
150      * The input object will be cloned using one of these techniques (in order):
151      * <ul>
152      * <li>public clone method</li>
153      * <li>public copy constructor</li>
154      * <li>serialization clone</li>
155      * </ul>
156      *
157      * @param <T>  the input/output type
158      * @return the transformer
159      * @see CloneTransformer
160      */
161     public static <T> Transformer<T, T> cloneTransformer() {
162         return CloneTransformer.cloneTransformer();
163     }
164 
165     /**
166      * Creates a Transformer that will return the same object each time the
167      * transformer is used.
168      *
169      * @param <I>  the input type
170      * @param <O>  the output type
171      * @param constantToReturn  the constant object to return each time in the transformer
172      * @return the transformer.
173      * @see ConstantTransformer
174      */
175     public static <I, O> Transformer<I, O> constantTransformer(final O constantToReturn) {
176         return ConstantTransformer.constantTransformer(constantToReturn);
177     }
178 
179     /**
180      * Gets a transformer that always throws an exception.
181      * This could be useful during testing as a placeholder.
182      *
183      * @param <I>  the input type
184      * @param <O>  the output type
185      * @return the transformer
186      * @see ExceptionTransformer
187      */
188     public static <I, O> Transformer<I, O> exceptionTransformer() {
189         return ExceptionTransformer.exceptionTransformer();
190     }
191 
192     /**
193      * Create a new Transformer that calls one of two transformers depending
194      * on the specified predicate.
195      *
196      * @param <I>  the input type
197      * @param <O>  the output type
198      * @param predicate  the predicate to switch on
199      * @param trueTransformer  the transformer called if the predicate is true
200      * @param falseTransformer  the transformer called if the predicate is false
201      * @return the transformer
202      * @throws NullPointerException if either the predicate or transformer is null
203      * @see IfTransformer
204      * @since 4.1
205      */
206     public static <I, O> Transformer<I, O> ifTransformer(final Predicate<? super I> predicate,
207                                                          final Transformer<? super I, ? extends O> trueTransformer,
208                                                          final Transformer<? super I, ? extends O> falseTransformer) {
209         return IfTransformer.ifTransformer(predicate, trueTransformer, falseTransformer);
210     }
211 
212     /**
213      * Create a new Transformer that calls the transformer if the predicate is true,
214      * otherwise the input object is returned unchanged.
215      *
216      * @param <T>  the input / output type
217      * @param predicate  the predicate to switch on
218      * @param trueTransformer  the transformer called if the predicate is true
219      * @return the transformer
220      * @throws NullPointerException if either the predicate or transformer is null
221      * @see IfTransformer
222      * @since 4.1
223      */
224     public static <T> Transformer<T, T> ifTransformer(final Predicate<? super T> predicate,
225                                                       final Transformer<? super T, ? extends T> trueTransformer) {
226         return IfTransformer.ifTransformer(predicate, trueTransformer);
227     }
228 
229     /**
230      * Gets a Transformer that expects an input Class object that it will instantiate.
231      *
232      * @param <T>  the output type
233      * @return the transformer
234      * @see InstantiateTransformer
235      */
236     public static <T> Transformer<Class<? extends T>, T> instantiateTransformer() {
237         return InstantiateTransformer.instantiateTransformer();
238     }
239 
240     /**
241      * Creates a Transformer that expects an input Class object that it will
242      * instantiate. The constructor used is determined by the arguments specified
243      * to this method.
244      *
245      * @param <T>  the output type
246      * @param paramTypes  parameter types for the constructor, can be null
247      * @param args  the arguments to pass to the constructor, can be null
248      * @return the transformer
249      * @throws IllegalArgumentException if the paramTypes and args don't match
250      * @see InstantiateTransformer
251      */
252     public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(
253             final Class<?>[] paramTypes, final Object[] args) {
254         return InstantiateTransformer.instantiateTransformer(paramTypes, args);
255     }
256 
257     /**
258      * Gets a Transformer that invokes a method on the input object.
259      * The method must have no parameters. If the input object is {@code null},
260      * {@code null} is returned.
261      *
262      * <p>
263      * For example, {@code TransformerUtils.invokerTransformer("getName");}
264      * will call the {@code getName} method on the input object to
265      * determine the transformer result.
266      * </p>
267      *
268      * @param <I>  the input type
269      * @param <O>  the output type
270      * @param methodName  the method name to call on the input object, may not be null
271      * @return the transformer
272      * @throws NullPointerException if the methodName is null.
273      * @see InvokerTransformer
274      */
275     public static <I, O> Transformer<I, O> invokerTransformer(final String methodName) {
276         return InvokerTransformer.invokerTransformer(methodName, null, null);
277     }
278 
279     /**
280      * Gets a Transformer that invokes a method on the input object.
281      * The method parameters are specified. If the input object is {@code null},
282      * {@code null} is returned.
283      *
284      * @param <I>  the input type
285      * @param <O>  the output type
286      * @param methodName  the name of the method
287      * @param paramTypes  the parameter types
288      * @param args  the arguments
289      * @return the transformer
290      * @throws NullPointerException if the method name is null
291      * @throws IllegalArgumentException if the paramTypes and args don't match
292      * @see InvokerTransformer
293      */
294     public static <I, O> Transformer<I, O> invokerTransformer(final String methodName, final Class<?>[] paramTypes,
295                                                               final Object[] args) {
296         return InvokerTransformer.invokerTransformer(methodName, paramTypes, args);
297     }
298 
299     /**
300      * Creates a Transformer that uses the passed in Map to transform the input
301      * object (as a simple lookup).
302      *
303      * @param <I>  the input type
304      * @param <O>  the output type
305      * @param map  the map to use to transform the objects
306      * @return the transformer, or {@link ConstantTransformer#nullTransformer()} if the
307      *   {@code map} is {@code null}
308      * @see MapTransformer
309      */
310     public static <I, O> Transformer<I, O> mapTransformer(final Map<? super I, ? extends O> map) {
311         return MapTransformer.mapTransformer(map);
312     }
313 
314     /**
315      * Gets a transformer that returns the input object.
316      * The input object should be immutable to maintain the
317      * contract of Transformer (although this is not checked).
318      *
319      * @param <T>  the input/output type
320      * @return the transformer
321      * @see NOPTransformer
322      */
323     public static <T> Transformer<T, T> nopTransformer() {
324         return NOPTransformer.nopTransformer();
325     }
326 
327     /**
328      * Gets a transformer that always returns null.
329      *
330      * @param <I>  the input type
331      * @param <O>  the output type
332      * @return the transformer
333      * @see ConstantTransformer
334      */
335     public static <I, O> Transformer<I, O> nullTransformer() {
336         return ConstantTransformer.nullTransformer();
337     }
338 
339     /**
340      * Gets a transformer that returns a {@link String}
341      * representation of the input object. This is achieved via the
342      * {@code toString} method, {@code null} returns 'null'.
343      *
344      * @param <T>  the input type
345      * @return the transformer
346      * @see StringValueTransformer
347      */
348     public static <T> Transformer<T, String> stringValueTransformer() {
349         return StringValueTransformer.stringValueTransformer();
350     }
351 
352     /**
353      * Create a new Transformer that uses the input object as a key to find the
354      * transformer to call.
355      * <p>
356      * The Map consists of object keys and Transformer values. A transformer
357      * is called if the input object equals the key. If there is no match, the
358      * default transformer is called. The default transformer is set in the map
359      * using a null key. If no default is set, null will be returned in a default case.
360      *
361      * @param <I>  the input type
362      * @param <O>  the output type
363      * @param objectsAndTransformers  a map of objects to transformers
364      * @return the transformer
365      * @throws NullPointerException if the map is null
366      * @throws NullPointerException if any transformer in the map is null
367      * @see SwitchTransformer
368      */
369     @SuppressWarnings("unchecked")
370     public static <I, O> Transformer<I, O> switchMapTransformer(
371             final Map<I, Transformer<I, O>> objectsAndTransformers) {
372 
373         Objects.requireNonNull(objectsAndTransformers, "objectsAndTransformers");
374         final Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null);
375         final int size = objectsAndTransformers.size();
376         final Transformer<? super I, ? extends O>[] trs = new Transformer[size];
377         final Predicate<I>[] preds = new Predicate[size];
378         int i = 0;
379         for (final Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
380             preds[i] = EqualPredicate.<I>equalPredicate(entry.getKey());
381             trs[i++] = entry.getValue();
382         }
383         return TransformerUtils.switchTransformer(preds, trs, def);
384     }
385 
386     /**
387      * Create a new Transformer that calls one of the transformers depending
388      * on the predicates.
389      * <p>
390      * The Map consists of Predicate keys and Transformer values. A transformer
391      * is called if its matching predicate returns true. Each predicate is evaluated
392      * until one returns true. If no predicates evaluate to true, the default
393      * transformer is called. The default transformer is set in the map with a
394      * null key. If no default transformer is set, null will be returned in a default
395      * case. The ordering is that of the iterator() method on the entryset collection
396      * of the map.
397      *
398      * @param <I>  the input type
399      * @param <O>  the output type
400      * @param predicatesAndTransformers  a map of predicates to transformers
401      * @return the transformer
402      * @throws NullPointerException if the map is null
403      * @throws NullPointerException if any transformer in the map is null
404      * @throws ClassCastException  if the map elements are of the wrong type
405      * @see SwitchTransformer
406      */
407     public static <I, O> Transformer<I, O> switchTransformer(
408             final Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers) {
409         return SwitchTransformer.switchTransformer(predicatesAndTransformers);
410     }
411 
412     /**
413      * Create a new Transformer that calls one of two transformers depending
414      * on the specified predicate.
415      *
416      * @param <I>  the input type
417      * @param <O>  the output type
418      * @param predicate  the predicate to switch on
419      * @param trueTransformer  the transformer called if the predicate is true
420      * @param falseTransformer  the transformer called if the predicate is false
421      * @return the transformer
422      * @throws NullPointerException if either the predicate or transformer is null
423      * @see SwitchTransformer
424      * @deprecated as of 4.1, use {@link #ifTransformer(Predicate, Transformer, Transformer)}
425      */
426     @SuppressWarnings("unchecked")
427     @Deprecated
428     public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I> predicate,
429             final Transformer<? super I, ? extends O> trueTransformer,
430             final Transformer<? super I, ? extends O> falseTransformer) {
431         return SwitchTransformer.switchTransformer(new Predicate[] { predicate },
432                                                    new Transformer[] { trueTransformer }, falseTransformer);
433     }
434 
435     /**
436      * Create a new Transformer that calls one of the transformers depending
437      * on the predicates. The transformer at array location 0 is called if the
438      * predicate at array location 0 returned true. Each predicate is evaluated
439      * until one returns true. If no predicates evaluate to true, null is returned.
440      *
441      * @param <I>  the input type
442      * @param <O>  the output type
443      * @param predicates  an array of predicates to check
444      * @param transformers  an array of transformers to call
445      * @return the transformer
446      * @throws NullPointerException if either array is null
447      * @throws NullPointerException if any element in the arrays is null
448      * @throws IllegalArgumentException if the arrays have different sizes
449      * @see SwitchTransformer
450      */
451     public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
452             final Transformer<? super I, ? extends O>[] transformers) {
453         return SwitchTransformer.switchTransformer(predicates, transformers, null);
454     }
455 
456     /**
457      * Create a new Transformer that calls one of the transformers depending
458      * on the predicates. The transformer at array location 0 is called if the
459      * predicate at array location 0 returned true. Each predicate is evaluated
460      * until one returns true. If no predicates evaluate to true, the default
461      * transformer is called. If the default transformer is null, null is returned.
462      *
463      * @param <I>  the input type
464      * @param <O>  the output type
465      * @param predicates  an array of predicates to check
466      * @param transformers  an array of transformers to call
467      * @param defaultTransformer  the default to call if no predicate matches, null means return null
468      * @return the transformer
469      * @throws NullPointerException if either array is null
470      * @throws NullPointerException if any element in the arrays is null
471      * @throws IllegalArgumentException if the arrays have different sizes
472      * @see SwitchTransformer
473      */
474     public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
475             final Transformer<? super I, ? extends O>[] transformers,
476             final Transformer<? super I, ? extends O> defaultTransformer) {
477         return SwitchTransformer.switchTransformer(predicates, transformers, defaultTransformer);
478     }
479 
480     /**
481      * This class is not normally instantiated.
482      */
483     private TransformerUtils() {}
484 
485 }