    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}