001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.collections4;
018
019import java.util.Collection;
020import java.util.Map;
021
022import org.apache.commons.collections4.functors.ChainedTransformer;
023import org.apache.commons.collections4.functors.CloneTransformer;
024import org.apache.commons.collections4.functors.ClosureTransformer;
025import org.apache.commons.collections4.functors.ConstantTransformer;
026import org.apache.commons.collections4.functors.EqualPredicate;
027import org.apache.commons.collections4.functors.ExceptionTransformer;
028import org.apache.commons.collections4.functors.FactoryTransformer;
029import org.apache.commons.collections4.functors.IfTransformer;
030import org.apache.commons.collections4.functors.InstantiateTransformer;
031import org.apache.commons.collections4.functors.InvokerTransformer;
032import org.apache.commons.collections4.functors.MapTransformer;
033import org.apache.commons.collections4.functors.NOPTransformer;
034import org.apache.commons.collections4.functors.PredicateTransformer;
035import org.apache.commons.collections4.functors.StringValueTransformer;
036import org.apache.commons.collections4.functors.SwitchTransformer;
037
038/**
039 * <code>TransformerUtils</code> provides reference implementations and
040 * utilities for the Transformer functor interface. The supplied transformers are:
041 * <ul>
042 * <li>Invoker - returns the result of a method call on the input object
043 * <li>Clone - returns a clone of the input object
044 * <li>Constant - always returns the same object
045 * <li>Closure - performs a Closure and returns the input object
046 * <li>Predicate - returns the result of the predicate as a Boolean
047 * <li>Factory - returns a new object from a factory
048 * <li>Chained - chains two or more transformers together
049 * <li>If - calls one transformer or another based on a predicate
050 * <li>Switch - calls one transformer based on one or more predicates
051 * <li>SwitchMap - calls one transformer looked up from a Map
052 * <li>Instantiate - the Class input object is instantiated
053 * <li>Map - returns an object from a supplied Map
054 * <li>Null - always returns null
055 * <li>NOP - returns the input object, which should be immutable
056 * <li>Exception - always throws an exception
057 * <li>StringValue - returns a <code>java.lang.String</code> representation of the input object
058 * </ul>
059 * <p>
060 * Since v4.1 only transformers which are considered to be safe are
061 * Serializable. Transformers considered to be unsafe for serialization are:
062 * </p>
063 * <ul>
064 * <li>Invoker
065 * <li>Clone
066 * <li>Instantiate
067 * </ul>
068 *
069 * @since 3.0
070 */
071public class TransformerUtils {
072
073    /**
074     * This class is not normally instantiated.
075     */
076    private TransformerUtils() {}
077
078    /**
079     * Gets a transformer that always throws an exception.
080     * This could be useful during testing as a placeholder.
081     *
082     * @param <I>  the input type
083     * @param <O>  the output type
084     * @return the transformer
085     * @see ExceptionTransformer
086     */
087    public static <I, O> Transformer<I, O> exceptionTransformer() {
088        return ExceptionTransformer.exceptionTransformer();
089    }
090
091    /**
092     * Gets a transformer that always returns null.
093     *
094     * @param <I>  the input type
095     * @param <O>  the output type
096     * @return the transformer
097     * @see ConstantTransformer
098     */
099    public static <I, O> Transformer<I, O> nullTransformer() {
100        return ConstantTransformer.nullTransformer();
101    }
102
103    /**
104     * Gets a transformer that returns the input object.
105     * The input object should be immutable to maintain the
106     * contract of Transformer (although this is not checked).
107     *
108     * @param <T>  the input/output type
109     * @return the transformer
110     * @see NOPTransformer
111     */
112    public static <T> Transformer<T, T> nopTransformer() {
113        return NOPTransformer.nopTransformer();
114    }
115
116    /**
117     * Gets a transformer that returns a clone of the input object.
118     * The input object will be cloned using one of these techniques (in order):
119     * <ul>
120     * <li>public clone method</li>
121     * <li>public copy constructor</li>
122     * <li>serialization clone</li>
123     * </ul>
124     *
125     * @param <T>  the input/output type
126     * @return the transformer
127     * @see CloneTransformer
128     */
129    public static <T> Transformer<T, T> cloneTransformer() {
130        return CloneTransformer.cloneTransformer();
131    }
132
133    /**
134     * Creates a Transformer that will return the same object each time the
135     * transformer is used.
136     *
137     * @param <I>  the input type
138     * @param <O>  the output type
139     * @param constantToReturn  the constant object to return each time in the transformer
140     * @return the transformer.
141     * @see ConstantTransformer
142     */
143    public static <I, O> Transformer<I, O> constantTransformer(final O constantToReturn) {
144        return ConstantTransformer.constantTransformer(constantToReturn);
145    }
146
147    /**
148     * Creates a Transformer that calls a Closure each time the transformer is used.
149     * The transformer returns the input object.
150     *
151     * @param <T>  the input/output type
152     * @param closure  the closure to run each time in the transformer, not null
153     * @return the transformer
154     * @throws NullPointerException if the closure is null
155     * @see ClosureTransformer
156     */
157    public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) {
158        return ClosureTransformer.closureTransformer(closure);
159    }
160
161    /**
162     * Creates a Transformer that calls a Predicate each time the transformer is used.
163     * The transformer will return either Boolean.TRUE or Boolean.FALSE.
164     *
165     * @param <T>  the input type
166     * @param predicate  the predicate to run each time in the transformer, not null
167     * @return the transformer
168     * @throws NullPointerException if the predicate is null
169     * @see PredicateTransformer
170     */
171    public static <T> Transformer<T, Boolean> asTransformer(final Predicate<? super T> predicate) {
172        return PredicateTransformer.predicateTransformer(predicate);
173    }
174
175    /**
176     * Creates a Transformer that calls a Factory each time the transformer is used.
177     * The transformer will return the value returned by the factory.
178     *
179     * @param <I>  the input type
180     * @param <O>  the output type
181     * @param factory  the factory to run each time in the transformer, not null
182     * @return the transformer
183     * @throws NullPointerException if the factory is null
184     * @see FactoryTransformer
185     */
186    public static <I, O> Transformer<I, O> asTransformer(final Factory<? extends O> factory) {
187        return FactoryTransformer.factoryTransformer(factory);
188    }
189
190    /**
191     * Create a new Transformer that calls each transformer in turn, passing the
192     * result into the next transformer.
193     *
194     * @param <T>  the input/output type
195     * @param transformers  an array of transformers to chain
196     * @return the transformer
197     * @throws NullPointerException if the transformers array or any of the transformers is null
198     * @see ChainedTransformer
199     */
200    public static <T> Transformer<T, T> chainedTransformer(
201            final Transformer<? super T, ? extends T>... transformers) {
202        return ChainedTransformer.chainedTransformer(transformers);
203    }
204
205    /**
206     * Create a new Transformer that calls each transformer in turn, passing the
207     * result into the next transformer. The ordering is that of the iterator()
208     * method on the collection.
209     *
210     * @param <T>  the input/output type
211     * @param transformers  a collection of transformers to chain
212     * @return the transformer
213     * @throws NullPointerException if the transformers collection or any of the transformers is null
214     * @see ChainedTransformer
215     */
216    public static <T> Transformer<T, T> chainedTransformer(
217            final Collection<? extends Transformer<? super T, ? extends T>> transformers) {
218        return ChainedTransformer.chainedTransformer(transformers);
219    }
220
221    /**
222     * Create a new Transformer that calls the transformer if the predicate is true,
223     * otherwise the input object is returned unchanged.
224     *
225     * @param <T>  the input / output type
226     * @param predicate  the predicate to switch on
227     * @param trueTransformer  the transformer called if the predicate is true
228     * @return the transformer
229     * @throws NullPointerException if either the predicate or transformer is null
230     * @see IfTransformer
231     * @since 4.1
232     */
233    public static <T> Transformer<T, T> ifTransformer(final Predicate<? super T> predicate,
234                                                      final Transformer<? super T, ? extends T> trueTransformer) {
235        return IfTransformer.ifTransformer(predicate, trueTransformer);
236    }
237
238    /**
239     * Create a new Transformer that calls one of two transformers depending
240     * on the specified predicate.
241     *
242     * @param <I>  the input type
243     * @param <O>  the output type
244     * @param predicate  the predicate to switch on
245     * @param trueTransformer  the transformer called if the predicate is true
246     * @param falseTransformer  the transformer called if the predicate is false
247     * @return the transformer
248     * @throws NullPointerException if either the predicate or transformer is null
249     * @see IfTransformer
250     * @since 4.1
251     */
252    public static <I, O> Transformer<I, O> ifTransformer(final Predicate<? super I> predicate,
253                                                         final Transformer<? super I, ? extends O> trueTransformer,
254                                                         final Transformer<? super I, ? extends O> falseTransformer) {
255        return IfTransformer.ifTransformer(predicate, trueTransformer, falseTransformer);
256    }
257
258    /**
259     * Create a new Transformer that calls one of two transformers depending
260     * on the specified predicate.
261     *
262     * @param <I>  the input type
263     * @param <O>  the output type
264     * @param predicate  the predicate to switch on
265     * @param trueTransformer  the transformer called if the predicate is true
266     * @param falseTransformer  the transformer called if the predicate is false
267     * @return the transformer
268     * @throws NullPointerException if either the predicate or transformer is null
269     * @see SwitchTransformer
270     * @deprecated as of 4.1, use {@link #ifTransformer(Predicate, Transformer, Transformer)}
271     */
272    @SuppressWarnings("unchecked")
273    @Deprecated
274    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I> predicate,
275            final Transformer<? super I, ? extends O> trueTransformer,
276            final Transformer<? super I, ? extends O> falseTransformer) {
277        return SwitchTransformer.switchTransformer(new Predicate[] { predicate },
278                                                   new Transformer[] { trueTransformer }, falseTransformer);
279    }
280
281    /**
282     * Create a new Transformer that calls one of the transformers depending
283     * on the predicates. The transformer at array location 0 is called if the
284     * predicate at array location 0 returned true. Each predicate is evaluated
285     * until one returns true. If no predicates evaluate to true, null is returned.
286     *
287     * @param <I>  the input type
288     * @param <O>  the output type
289     * @param predicates  an array of predicates to check
290     * @param transformers  an array of transformers to call
291     * @return the transformer
292     * @throws NullPointerException if the either array is null
293     * @throws NullPointerException if any element in the arrays is null
294     * @throws IllegalArgumentException if the arrays have different sizes
295     * @see SwitchTransformer
296     */
297    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
298            final Transformer<? super I, ? extends O>[] transformers) {
299        return SwitchTransformer.switchTransformer(predicates, transformers, null);
300    }
301
302    /**
303     * Create a new Transformer that calls one of the transformers depending
304     * on the predicates. The transformer at array location 0 is called if the
305     * predicate at array location 0 returned true. Each predicate is evaluated
306     * until one returns true. If no predicates evaluate to true, the default
307     * transformer is called. If the default transformer is null, null is returned.
308     *
309     * @param <I>  the input type
310     * @param <O>  the output type
311     * @param predicates  an array of predicates to check
312     * @param transformers  an array of transformers to call
313     * @param defaultTransformer  the default to call if no predicate matches, null means return null
314     * @return the transformer
315     * @throws NullPointerException if the either array is null
316     * @throws NullPointerException if any element in the arrays is null
317     * @throws IllegalArgumentException if the arrays have different sizes
318     * @see SwitchTransformer
319     */
320    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
321            final Transformer<? super I, ? extends O>[] transformers,
322            final Transformer<? super I, ? extends O> defaultTransformer) {
323        return SwitchTransformer.switchTransformer(predicates, transformers, defaultTransformer);
324    }
325
326    /**
327     * Create a new Transformer that calls one of the transformers depending
328     * on the predicates.
329     * <p>
330     * The Map consists of Predicate keys and Transformer values. A transformer
331     * is called if its matching predicate returns true. Each predicate is evaluated
332     * until one returns true. If no predicates evaluate to true, the default
333     * transformer is called. The default transformer is set in the map with a
334     * null key. If no default transformer is set, null will be returned in a default
335     * case. The ordering is that of the iterator() method on the entryset collection
336     * of the map.
337     *
338     * @param <I>  the input type
339     * @param <O>  the output type
340     * @param predicatesAndTransformers  a map of predicates to transformers
341     * @return the transformer
342     * @throws NullPointerException if the map is null
343     * @throws NullPointerException if any transformer in the map is null
344     * @throws ClassCastException  if the map elements are of the wrong type
345     * @see SwitchTransformer
346     */
347    public static <I, O> Transformer<I, O> switchTransformer(
348            final Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers) {
349        return SwitchTransformer.switchTransformer(predicatesAndTransformers);
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        if (objectsAndTransformers == null) {
374            throw new NullPointerException("The object and transformer map must not be null");
375        }
376        final Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null);
377        final int size = objectsAndTransformers.size();
378        final Transformer<? super I, ? extends O>[] trs = new Transformer[size];
379        final Predicate<I>[] preds = new Predicate[size];
380        int i = 0;
381        for (final Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
382            preds[i] = EqualPredicate.<I>equalPredicate(entry.getKey());
383            trs[i++] = entry.getValue();
384        }
385        return TransformerUtils.switchTransformer(preds, trs, def);
386    }
387
388    /**
389     * Gets a Transformer that expects an input Class object that it will instantiate.
390     *
391     * @param <T>  the output type
392     * @return the transformer
393     * @see InstantiateTransformer
394     */
395    public static <T> Transformer<Class<? extends T>, T> instantiateTransformer() {
396        return InstantiateTransformer.instantiateTransformer();
397    }
398
399    /**
400     * Creates a Transformer that expects an input Class object that it will
401     * instantiate. The constructor used is determined by the arguments specified
402     * to this method.
403     *
404     * @param <T>  the output type
405     * @param paramTypes  parameter types for the constructor, can be null
406     * @param args  the arguments to pass to the constructor, can be null
407     * @return the transformer
408     * @throws IllegalArgumentException if the paramTypes and args don't match
409     * @see InstantiateTransformer
410     */
411    public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(
412            final Class<?>[] paramTypes, final Object[] args) {
413        return InstantiateTransformer.instantiateTransformer(paramTypes, args);
414    }
415
416    /**
417     * Creates a Transformer that uses the passed in Map to transform the input
418     * object (as a simple lookup).
419     *
420     * @param <I>  the input type
421     * @param <O>  the output type
422     * @param map  the map to use to transform the objects
423     * @return the transformer, or {@link ConstantTransformer#nullTransformer()} if the
424     *   {@code map} is {@code null}
425     * @see MapTransformer
426     */
427    public static <I, O> Transformer<I, O> mapTransformer(final Map<? super I, ? extends O> map) {
428        return MapTransformer.mapTransformer(map);
429    }
430
431    /**
432     * Gets a Transformer that invokes a method on the input object.
433     * The method must have no parameters. If the input object is {@code null},
434     * {@code null} is returned.
435     *
436     * <p>
437     * For example, <code>TransformerUtils.invokerTransformer("getName");</code>
438     * will call the <code>getName</code> method on the input object to
439     * determine the transformer result.
440     * </p>
441     *
442     * @param <I>  the input type
443     * @param <O>  the output type
444     * @param methodName  the method name to call on the input object, may not be null
445     * @return the transformer
446     * @throws NullPointerException if the methodName is null.
447     * @see InvokerTransformer
448     */
449    public static <I, O> Transformer<I, O> invokerTransformer(final String methodName) {
450        return InvokerTransformer.invokerTransformer(methodName, null, null);
451    }
452
453    /**
454     * Gets a Transformer that invokes a method on the input object.
455     * The method parameters are specified. If the input object is {@code null},
456     * {@code null} is returned.
457     *
458     * @param <I>  the input type
459     * @param <O>  the output type
460     * @param methodName  the name of the method
461     * @param paramTypes  the parameter types
462     * @param args  the arguments
463     * @return the transformer
464     * @throws NullPointerException if the method name is null
465     * @throws IllegalArgumentException if the paramTypes and args don't match
466     * @see InvokerTransformer
467     */
468    public static <I, O> Transformer<I, O> invokerTransformer(final String methodName, final Class<?>[] paramTypes,
469                                                              final Object[] args) {
470        return InvokerTransformer.invokerTransformer(methodName, paramTypes, args);
471    }
472
473    /**
474     * Gets a transformer that returns a <code>java.lang.String</code>
475     * representation of the input object. This is achieved via the
476     * <code>toString</code> method, <code>null</code> returns 'null'.
477     *
478     * @param <T>  the input type
479     * @return the transformer
480     * @see StringValueTransformer
481     */
482    public static <T> Transformer<T, String> stringValueTransformer() {
483        return StringValueTransformer.stringValueTransformer();
484    }
485
486}