    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;
    021import java.util.Objects;
    022
    023import org.apache.commons.collections4.functors.ChainedTransformer;
    024import org.apache.commons.collections4.functors.CloneTransformer;
    025import org.apache.commons.collections4.functors.ClosureTransformer;
    026import org.apache.commons.collections4.functors.ConstantTransformer;
    027import org.apache.commons.collections4.functors.EqualPredicate;
    028import org.apache.commons.collections4.functors.ExceptionTransformer;
    029import org.apache.commons.collections4.functors.FactoryTransformer;
    030import org.apache.commons.collections4.functors.IfTransformer;
    031import org.apache.commons.collections4.functors.InstantiateTransformer;
    032import org.apache.commons.collections4.functors.InvokerTransformer;
    033import org.apache.commons.collections4.functors.MapTransformer;
    034import org.apache.commons.collections4.functors.NOPTransformer;
    035import org.apache.commons.collections4.functors.PredicateTransformer;
    036import org.apache.commons.collections4.functors.StringValueTransformer;
    037import org.apache.commons.collections4.functors.SwitchTransformer;
    038
    039/**
    040 * {@code TransformerUtils} provides reference implementations and
    041 * utilities for the Transformer functor interface. The supplied transformers are:
    042 * <ul>
    043 * <li>Invoker - returns the result of a method call on the input object
    044 * <li>Clone - returns a clone of the input object
    045 * <li>Constant - always returns the same object
    046 * <li>Closure - performs a Closure and returns the input object
    047 * <li>Predicate - returns the result of the predicate as a Boolean
    048 * <li>Factory - returns a new object from a factory
    049 * <li>Chained - chains two or more transformers together
    050 * <li>If - calls one transformer or another based on a predicate
    051 * <li>Switch - calls one transformer based on one or more predicates
    052 * <li>SwitchMap - calls one transformer looked up from a Map
    053 * <li>Instantiate - the Class input object is instantiated
    054 * <li>Map - returns an object from a supplied Map
    055 * <li>Null - always returns null
    056 * <li>NOP - returns the input object, which should be immutable
    057 * <li>Exception - always throws an exception
    058 * <li>StringValue - returns a {@link String} representation of the input object
    059 * </ul>
    060 * <p>
    061 * Since v4.1 only transformers which are considered to be safe are
    062 * Serializable. Transformers considered to be unsafe for serialization are:
    063 * </p>
    064 * <ul>
    065 * <li>Invoker
    066 * <li>Clone
    067 * <li>Instantiate
    068 * </ul>
    069 *
    070 * @since 3.0
    071 */
    072public class TransformerUtils {
    073
    074    /**
    075     * Creates a Transformer that calls a Closure each time the transformer is used.
    076     * The transformer returns the input object.
    077     *
    078     * @param <T>  the input/output type
    079     * @param closure  the closure to run each time in the transformer, not null
    080     * @return the transformer
    081     * @throws NullPointerException if the closure is null
    082     * @see ClosureTransformer
    083     */
    084    public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) {
    085        return ClosureTransformer.closureTransformer(closure);
    086    }
    087
    088    /**
    089     * Creates a Transformer that calls a Factory each time the transformer is used.
    090     * The transformer will return the value returned by the factory.
    091     *
    092     * @param <I>  the input type
    093     * @param <O>  the output type
    094     * @param factory  the factory to run each time in the transformer, not null
    095     * @return the transformer
    096     * @throws NullPointerException if the factory is null
    097     * @see FactoryTransformer
    098     */
    099    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     * </p>
    361     *
    362     * @param <I>  the input type
    363     * @param <O>  the output type
    364     * @param objectsAndTransformers  a map of objects to transformers
    365     * @return the transformer
    366     * @throws NullPointerException if the map is null
    367     * @throws NullPointerException if any transformer in the map is null
    368     * @see SwitchTransformer
    369     */
    370    @SuppressWarnings("unchecked")
    371    public static <I, O> Transformer<I, O> switchMapTransformer(
    372            final Map<I, Transformer<I, O>> objectsAndTransformers) {
    373
    374        Objects.requireNonNull(objectsAndTransformers, "objectsAndTransformers");
    375        final Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null);
    376        final int size = objectsAndTransformers.size();
    377        final Transformer<? super I, ? extends O>[] trs = new Transformer[size];
    378        final Predicate<I>[] preds = new Predicate[size];
    379        int i = 0;
    380        for (final Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
    381            preds[i] = EqualPredicate.<I>equalPredicate(entry.getKey());
    382            trs[i++] = entry.getValue();
    383        }
    384        return switchTransformer(preds, trs, def);
    385    }
    386
    387    /**
    388     * Create a new Transformer that calls one of the transformers depending
    389     * on the predicates.
    390     * <p>
    391     * The Map consists of Predicate keys and Transformer values. A transformer
    392     * is called if its matching predicate returns true. Each predicate is evaluated
    393     * until one returns true. If no predicates evaluate to true, the default
    394     * transformer is called. The default transformer is set in the map with a
    395     * null key. If no default transformer is set, null will be returned in a default
    396     * case. The ordering is that of the iterator() method on the entryset collection
    397     * of the map.
    398     * </p>
    399     *
    400     * @param <I>  the input type
    401     * @param <O>  the output type
    402     * @param predicatesAndTransformers  a map of predicates to transformers
    403     * @return the transformer
    404     * @throws NullPointerException if the map is null
    405     * @throws NullPointerException if any transformer in the map is null
    406     * @throws ClassCastException  if the map elements are of the wrong type
    407     * @see SwitchTransformer
    408     */
    409    public static <I, O> Transformer<I, O> switchTransformer(
    410            final Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers) {
    411        return SwitchTransformer.switchTransformer(predicatesAndTransformers);
    412    }
    413
    414    /**
    415     * Create a new Transformer that calls one of two transformers depending
    416     * on the specified predicate.
    417     *
    418     * @param <I>  the input type
    419     * @param <O>  the output type
    420     * @param predicate  the predicate to switch on
    421     * @param trueTransformer  the transformer called if the predicate is true
    422     * @param falseTransformer  the transformer called if the predicate is false
    423     * @return the transformer
    424     * @throws NullPointerException if either the predicate or transformer is null
    425     * @see SwitchTransformer
    426     * @deprecated as of 4.1, use {@link #ifTransformer(Predicate, Transformer, Transformer)}
    427     */
    428    @SuppressWarnings("unchecked")
    429    @Deprecated
    430    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I> predicate,
    431            final Transformer<? super I, ? extends O> trueTransformer,
    432            final Transformer<? super I, ? extends O> falseTransformer) {
    433        return SwitchTransformer.switchTransformer(new Predicate[] { predicate },
    434                                                   new Transformer[] { trueTransformer }, falseTransformer);
    435    }
    436
    437    /**
    438     * Create a new Transformer that calls one of the transformers depending
    439     * on the predicates. The transformer at array location 0 is called if the
    440     * predicate at array location 0 returned true. Each predicate is evaluated
    441     * until one returns true. If no predicates evaluate to true, null is returned.
    442     *
    443     * @param <I>  the input type
    444     * @param <O>  the output type
    445     * @param predicates  an array of predicates to check
    446     * @param transformers  an array of transformers to call
    447     * @return the transformer
    448     * @throws NullPointerException if either array is null
    449     * @throws NullPointerException if any element in the arrays is null
    450     * @throws IllegalArgumentException if the arrays have different sizes
    451     * @see SwitchTransformer
    452     */
    453    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
    454            final Transformer<? super I, ? extends O>[] transformers) {
    455        return SwitchTransformer.switchTransformer(predicates, transformers, null);
    456    }
    457
    458    /**
    459     * Create a new Transformer that calls one of the transformers depending
    460     * on the predicates. The transformer at array location 0 is called if the
    461     * predicate at array location 0 returned true. Each predicate is evaluated
    462     * until one returns true. If no predicates evaluate to true, the default
    463     * transformer is called. If the default transformer is null, null is returned.
    464     *
    465     * @param <I>  the input type
    466     * @param <O>  the output type
    467     * @param predicates  an array of predicates to check
    468     * @param transformers  an array of transformers to call
    469     * @param defaultTransformer  the default to call if no predicate matches, null means return null
    470     * @return the transformer
    471     * @throws NullPointerException if either array is null
    472     * @throws NullPointerException if any element in the arrays is null
    473     * @throws IllegalArgumentException if the arrays have different sizes
    474     * @see SwitchTransformer
    475     */
    476    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
    477            final Transformer<? super I, ? extends O>[] transformers,
    478            final Transformer<? super I, ? extends O> defaultTransformer) {
    479        return SwitchTransformer.switchTransformer(predicates, transformers, defaultTransformer);
    480    }
    481
    482    /**
    483     * This class is not normally instantiated.
    484     */
    485    private TransformerUtils() {
    486        // empty
    487    }
    488
    489}