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