TransformerUtils.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4;

  18. import java.util.Collection;
  19. import java.util.Map;
  20. import java.util.Objects;

  21. import org.apache.commons.collections4.functors.ChainedTransformer;
  22. import org.apache.commons.collections4.functors.CloneTransformer;
  23. import org.apache.commons.collections4.functors.ClosureTransformer;
  24. import org.apache.commons.collections4.functors.ConstantTransformer;
  25. import org.apache.commons.collections4.functors.EqualPredicate;
  26. import org.apache.commons.collections4.functors.ExceptionTransformer;
  27. import org.apache.commons.collections4.functors.FactoryTransformer;
  28. import org.apache.commons.collections4.functors.IfTransformer;
  29. import org.apache.commons.collections4.functors.InstantiateTransformer;
  30. import org.apache.commons.collections4.functors.InvokerTransformer;
  31. import org.apache.commons.collections4.functors.MapTransformer;
  32. import org.apache.commons.collections4.functors.NOPTransformer;
  33. import org.apache.commons.collections4.functors.PredicateTransformer;
  34. import org.apache.commons.collections4.functors.StringValueTransformer;
  35. import org.apache.commons.collections4.functors.SwitchTransformer;

  36. /**
  37.  * {@code TransformerUtils} provides reference implementations and
  38.  * utilities for the Transformer functor interface. The supplied transformers are:
  39.  * <ul>
  40.  * <li>Invoker - returns the result of a method call on the input object
  41.  * <li>Clone - returns a clone of the input object
  42.  * <li>Constant - always returns the same object
  43.  * <li>Closure - performs a Closure and returns the input object
  44.  * <li>Predicate - returns the result of the predicate as a Boolean
  45.  * <li>Factory - returns a new object from a factory
  46.  * <li>Chained - chains two or more transformers together
  47.  * <li>If - calls one transformer or another based on a predicate
  48.  * <li>Switch - calls one transformer based on one or more predicates
  49.  * <li>SwitchMap - calls one transformer looked up from a Map
  50.  * <li>Instantiate - the Class input object is instantiated
  51.  * <li>Map - returns an object from a supplied Map
  52.  * <li>Null - always returns null
  53.  * <li>NOP - returns the input object, which should be immutable
  54.  * <li>Exception - always throws an exception
  55.  * <li>StringValue - returns a {@link String} representation of the input object
  56.  * </ul>
  57.  * <p>
  58.  * Since v4.1 only transformers which are considered to be safe are
  59.  * Serializable. Transformers considered to be unsafe for serialization are:
  60.  * </p>
  61.  * <ul>
  62.  * <li>Invoker
  63.  * <li>Clone
  64.  * <li>Instantiate
  65.  * </ul>
  66.  *
  67.  * @since 3.0
  68.  */
  69. public class TransformerUtils {

  70.     /**
  71.      * Creates a Transformer that calls a Closure each time the transformer is used.
  72.      * The transformer returns the input object.
  73.      *
  74.      * @param <T>  the input/output type
  75.      * @param closure  the closure to run each time in the transformer, not null
  76.      * @return the transformer
  77.      * @throws NullPointerException if the closure is null
  78.      * @see ClosureTransformer
  79.      */
  80.     public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) {
  81.         return ClosureTransformer.closureTransformer(closure);
  82.     }

  83.     /**
  84.      * Creates a Transformer that calls a Factory each time the transformer is used.
  85.      * The transformer will return the value returned by the factory.
  86.      *
  87.      * @param <I>  the input type
  88.      * @param <O>  the output type
  89.      * @param factory  the factory to run each time in the transformer, not null
  90.      * @return the transformer
  91.      * @throws NullPointerException if the factory is null
  92.      * @see FactoryTransformer
  93.      */
  94.     public static <I, O> Transformer<I, O> asTransformer(final Factory<? extends O> factory) {
  95.         return FactoryTransformer.factoryTransformer(factory);
  96.     }

  97.     /**
  98.      * Creates a Transformer that calls a Predicate each time the transformer is used.
  99.      * The transformer will return either {@link Boolean#TRUE} or {@link Boolean#FALSE}.
  100.      *
  101.      * @param <T>  the input type
  102.      * @param predicate  the predicate to run each time in the transformer, not null
  103.      * @return the transformer
  104.      * @throws NullPointerException if the predicate is null
  105.      * @see PredicateTransformer
  106.      */
  107.     public static <T> Transformer<T, Boolean> asTransformer(final Predicate<? super T> predicate) {
  108.         return PredicateTransformer.predicateTransformer(predicate);
  109.     }

  110.     /**
  111.      * Create a new Transformer that calls each transformer in turn, passing the
  112.      * result into the next transformer. The ordering is that of the iterator()
  113.      * method on the collection.
  114.      *
  115.      * @param <T>  the input/output type
  116.      * @param transformers  a collection of transformers to chain
  117.      * @return the transformer
  118.      * @throws NullPointerException if the transformers collection or any of the transformers is null
  119.      * @see ChainedTransformer
  120.      */
  121.     public static <T> Transformer<T, T> chainedTransformer(
  122.             final Collection<? extends Transformer<? super T, ? extends T>> transformers) {
  123.         return ChainedTransformer.chainedTransformer(transformers);
  124.     }

  125.     /**
  126.      * Create a new Transformer that calls each transformer in turn, passing the
  127.      * result into the next transformer.
  128.      *
  129.      * @param <T>  the input/output type
  130.      * @param transformers  an array of transformers to chain
  131.      * @return the transformer
  132.      * @throws NullPointerException if the transformers array or any of the transformers is null
  133.      * @see ChainedTransformer
  134.      */
  135.     public static <T> Transformer<T, T> chainedTransformer(
  136.             final Transformer<? super T, ? extends T>... transformers) {
  137.         return ChainedTransformer.chainedTransformer(transformers);
  138.     }

  139.     /**
  140.      * Gets a transformer that returns a clone of the input object.
  141.      * The input object will be cloned using one of these techniques (in order):
  142.      * <ul>
  143.      * <li>public clone method</li>
  144.      * <li>public copy constructor</li>
  145.      * <li>serialization clone</li>
  146.      * </ul>
  147.      *
  148.      * @param <T>  the input/output type
  149.      * @return the transformer
  150.      * @see CloneTransformer
  151.      */
  152.     public static <T> Transformer<T, T> cloneTransformer() {
  153.         return CloneTransformer.cloneTransformer();
  154.     }

  155.     /**
  156.      * Creates a Transformer that will return the same object each time the
  157.      * transformer is used.
  158.      *
  159.      * @param <I>  the input type
  160.      * @param <O>  the output type
  161.      * @param constantToReturn  the constant object to return each time in the transformer
  162.      * @return the transformer.
  163.      * @see ConstantTransformer
  164.      */
  165.     public static <I, O> Transformer<I, O> constantTransformer(final O constantToReturn) {
  166.         return ConstantTransformer.constantTransformer(constantToReturn);
  167.     }

  168.     /**
  169.      * Gets a transformer that always throws an exception.
  170.      * This could be useful during testing as a placeholder.
  171.      *
  172.      * @param <I>  the input type
  173.      * @param <O>  the output type
  174.      * @return the transformer
  175.      * @see ExceptionTransformer
  176.      */
  177.     public static <I, O> Transformer<I, O> exceptionTransformer() {
  178.         return ExceptionTransformer.exceptionTransformer();
  179.     }

  180.     /**
  181.      * Create a new Transformer that calls one of two transformers depending
  182.      * on the specified predicate.
  183.      *
  184.      * @param <I>  the input type
  185.      * @param <O>  the output type
  186.      * @param predicate  the predicate to switch on
  187.      * @param trueTransformer  the transformer called if the predicate is true
  188.      * @param falseTransformer  the transformer called if the predicate is false
  189.      * @return the transformer
  190.      * @throws NullPointerException if either the predicate or transformer is null
  191.      * @see IfTransformer
  192.      * @since 4.1
  193.      */
  194.     public static <I, O> Transformer<I, O> ifTransformer(final Predicate<? super I> predicate,
  195.                                                          final Transformer<? super I, ? extends O> trueTransformer,
  196.                                                          final Transformer<? super I, ? extends O> falseTransformer) {
  197.         return IfTransformer.ifTransformer(predicate, trueTransformer, falseTransformer);
  198.     }

  199.     /**
  200.      * Create a new Transformer that calls the transformer if the predicate is true,
  201.      * otherwise the input object is returned unchanged.
  202.      *
  203.      * @param <T>  the input / output type
  204.      * @param predicate  the predicate to switch on
  205.      * @param trueTransformer  the transformer called if the predicate is true
  206.      * @return the transformer
  207.      * @throws NullPointerException if either the predicate or transformer is null
  208.      * @see IfTransformer
  209.      * @since 4.1
  210.      */
  211.     public static <T> Transformer<T, T> ifTransformer(final Predicate<? super T> predicate,
  212.                                                       final Transformer<? super T, ? extends T> trueTransformer) {
  213.         return IfTransformer.ifTransformer(predicate, trueTransformer);
  214.     }

  215.     /**
  216.      * Gets a Transformer that expects an input Class object that it will instantiate.
  217.      *
  218.      * @param <T>  the output type
  219.      * @return the transformer
  220.      * @see InstantiateTransformer
  221.      */
  222.     public static <T> Transformer<Class<? extends T>, T> instantiateTransformer() {
  223.         return InstantiateTransformer.instantiateTransformer();
  224.     }

  225.     /**
  226.      * Creates a Transformer that expects an input Class object that it will
  227.      * instantiate. The constructor used is determined by the arguments specified
  228.      * to this method.
  229.      *
  230.      * @param <T>  the output type
  231.      * @param paramTypes  parameter types for the constructor, can be null
  232.      * @param args  the arguments to pass to the constructor, can be null
  233.      * @return the transformer
  234.      * @throws IllegalArgumentException if the paramTypes and args don't match
  235.      * @see InstantiateTransformer
  236.      */
  237.     public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(
  238.             final Class<?>[] paramTypes, final Object[] args) {
  239.         return InstantiateTransformer.instantiateTransformer(paramTypes, args);
  240.     }

  241.     /**
  242.      * Gets a Transformer that invokes a method on the input object.
  243.      * The method must have no parameters. If the input object is {@code null},
  244.      * {@code null} is returned.
  245.      *
  246.      * <p>
  247.      * For example, {@code TransformerUtils.invokerTransformer("getName");}
  248.      * will call the {@code getName} method on the input object to
  249.      * determine the transformer result.
  250.      * </p>
  251.      *
  252.      * @param <I>  the input type
  253.      * @param <O>  the output type
  254.      * @param methodName  the method name to call on the input object, may not be null
  255.      * @return the transformer
  256.      * @throws NullPointerException if the methodName is null.
  257.      * @see InvokerTransformer
  258.      */
  259.     public static <I, O> Transformer<I, O> invokerTransformer(final String methodName) {
  260.         return InvokerTransformer.invokerTransformer(methodName, null, null);
  261.     }

  262.     /**
  263.      * Gets a Transformer that invokes a method on the input object.
  264.      * The method parameters are specified. If the input object is {@code null},
  265.      * {@code null} is returned.
  266.      *
  267.      * @param <I>  the input type
  268.      * @param <O>  the output type
  269.      * @param methodName  the name of the method
  270.      * @param paramTypes  the parameter types
  271.      * @param args  the arguments
  272.      * @return the transformer
  273.      * @throws NullPointerException if the method name is null
  274.      * @throws IllegalArgumentException if the paramTypes and args don't match
  275.      * @see InvokerTransformer
  276.      */
  277.     public static <I, O> Transformer<I, O> invokerTransformer(final String methodName, final Class<?>[] paramTypes,
  278.                                                               final Object[] args) {
  279.         return InvokerTransformer.invokerTransformer(methodName, paramTypes, args);
  280.     }

  281.     /**
  282.      * Creates a Transformer that uses the passed in Map to transform the input
  283.      * object (as a simple lookup).
  284.      *
  285.      * @param <I>  the input type
  286.      * @param <O>  the output type
  287.      * @param map  the map to use to transform the objects
  288.      * @return the transformer, or {@link ConstantTransformer#nullTransformer()} if the
  289.      *   {@code map} is {@code null}
  290.      * @see MapTransformer
  291.      */
  292.     public static <I, O> Transformer<I, O> mapTransformer(final Map<? super I, ? extends O> map) {
  293.         return MapTransformer.mapTransformer(map);
  294.     }

  295.     /**
  296.      * Gets a transformer that returns the input object.
  297.      * The input object should be immutable to maintain the
  298.      * contract of Transformer (although this is not checked).
  299.      *
  300.      * @param <T>  the input/output type
  301.      * @return the transformer
  302.      * @see NOPTransformer
  303.      */
  304.     public static <T> Transformer<T, T> nopTransformer() {
  305.         return NOPTransformer.nopTransformer();
  306.     }

  307.     /**
  308.      * Gets a transformer that always returns null.
  309.      *
  310.      * @param <I>  the input type
  311.      * @param <O>  the output type
  312.      * @return the transformer
  313.      * @see ConstantTransformer
  314.      */
  315.     public static <I, O> Transformer<I, O> nullTransformer() {
  316.         return ConstantTransformer.nullTransformer();
  317.     }

  318.     /**
  319.      * Gets a transformer that returns a {@link String}
  320.      * representation of the input object. This is achieved via the
  321.      * {@code toString} method, {@code null} returns 'null'.
  322.      *
  323.      * @param <T>  the input type
  324.      * @return the transformer
  325.      * @see StringValueTransformer
  326.      */
  327.     public static <T> Transformer<T, String> stringValueTransformer() {
  328.         return StringValueTransformer.stringValueTransformer();
  329.     }

  330.     /**
  331.      * Create a new Transformer that uses the input object as a key to find the
  332.      * transformer to call.
  333.      * <p>
  334.      * The Map consists of object keys and Transformer values. A transformer
  335.      * is called if the input object equals the key. If there is no match, the
  336.      * default transformer is called. The default transformer is set in the map
  337.      * using a null key. If no default is set, null will be returned in a default case.
  338.      * </p>
  339.      *
  340.      * @param <I>  the input type
  341.      * @param <O>  the output type
  342.      * @param objectsAndTransformers  a map of objects to transformers
  343.      * @return the transformer
  344.      * @throws NullPointerException if the map is null
  345.      * @throws NullPointerException if any transformer in the map is null
  346.      * @see SwitchTransformer
  347.      */
  348.     @SuppressWarnings("unchecked")
  349.     public static <I, O> Transformer<I, O> switchMapTransformer(
  350.             final Map<I, Transformer<I, O>> objectsAndTransformers) {

  351.         Objects.requireNonNull(objectsAndTransformers, "objectsAndTransformers");
  352.         final Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null);
  353.         final int size = objectsAndTransformers.size();
  354.         final Transformer<? super I, ? extends O>[] trs = new Transformer[size];
  355.         final Predicate<I>[] preds = new Predicate[size];
  356.         int i = 0;
  357.         for (final Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
  358.             preds[i] = EqualPredicate.<I>equalPredicate(entry.getKey());
  359.             trs[i++] = entry.getValue();
  360.         }
  361.         return switchTransformer(preds, trs, def);
  362.     }

  363.     /**
  364.      * Create a new Transformer that calls one of the transformers depending
  365.      * on the predicates.
  366.      * <p>
  367.      * The Map consists of Predicate keys and Transformer values. A transformer
  368.      * is called if its matching predicate returns true. Each predicate is evaluated
  369.      * until one returns true. If no predicates evaluate to true, the default
  370.      * transformer is called. The default transformer is set in the map with a
  371.      * null key. If no default transformer is set, null will be returned in a default
  372.      * case. The ordering is that of the iterator() method on the entryset collection
  373.      * of the map.
  374.      * </p>
  375.      *
  376.      * @param <I>  the input type
  377.      * @param <O>  the output type
  378.      * @param predicatesAndTransformers  a map of predicates to transformers
  379.      * @return the transformer
  380.      * @throws NullPointerException if the map is null
  381.      * @throws NullPointerException if any transformer in the map is null
  382.      * @throws ClassCastException  if the map elements are of the wrong type
  383.      * @see SwitchTransformer
  384.      */
  385.     public static <I, O> Transformer<I, O> switchTransformer(
  386.             final Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers) {
  387.         return SwitchTransformer.switchTransformer(predicatesAndTransformers);
  388.     }

  389.     /**
  390.      * Create a new Transformer that calls one of two transformers depending
  391.      * on the specified predicate.
  392.      *
  393.      * @param <I>  the input type
  394.      * @param <O>  the output type
  395.      * @param predicate  the predicate to switch on
  396.      * @param trueTransformer  the transformer called if the predicate is true
  397.      * @param falseTransformer  the transformer called if the predicate is false
  398.      * @return the transformer
  399.      * @throws NullPointerException if either the predicate or transformer is null
  400.      * @see SwitchTransformer
  401.      * @deprecated as of 4.1, use {@link #ifTransformer(Predicate, Transformer, Transformer)}
  402.      */
  403.     @SuppressWarnings("unchecked")
  404.     @Deprecated
  405.     public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I> predicate,
  406.             final Transformer<? super I, ? extends O> trueTransformer,
  407.             final Transformer<? super I, ? extends O> falseTransformer) {
  408.         return SwitchTransformer.switchTransformer(new Predicate[] { predicate },
  409.                                                    new Transformer[] { trueTransformer }, falseTransformer);
  410.     }

  411.     /**
  412.      * Create a new Transformer that calls one of the transformers depending
  413.      * on the predicates. The transformer at array location 0 is called if the
  414.      * predicate at array location 0 returned true. Each predicate is evaluated
  415.      * until one returns true. If no predicates evaluate to true, null is returned.
  416.      *
  417.      * @param <I>  the input type
  418.      * @param <O>  the output type
  419.      * @param predicates  an array of predicates to check
  420.      * @param transformers  an array of transformers to call
  421.      * @return the transformer
  422.      * @throws NullPointerException if either array is null
  423.      * @throws NullPointerException if any element in the arrays is null
  424.      * @throws IllegalArgumentException if the arrays have different sizes
  425.      * @see SwitchTransformer
  426.      */
  427.     public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
  428.             final Transformer<? super I, ? extends O>[] transformers) {
  429.         return SwitchTransformer.switchTransformer(predicates, transformers, null);
  430.     }

  431.     /**
  432.      * Create a new Transformer that calls one of the transformers depending
  433.      * on the predicates. The transformer at array location 0 is called if the
  434.      * predicate at array location 0 returned true. Each predicate is evaluated
  435.      * until one returns true. If no predicates evaluate to true, the default
  436.      * transformer is called. If the default transformer is null, null is returned.
  437.      *
  438.      * @param <I>  the input type
  439.      * @param <O>  the output type
  440.      * @param predicates  an array of predicates to check
  441.      * @param transformers  an array of transformers to call
  442.      * @param defaultTransformer  the default to call if no predicate matches, null means return null
  443.      * @return the transformer
  444.      * @throws NullPointerException if either array is null
  445.      * @throws NullPointerException if any element in the arrays is null
  446.      * @throws IllegalArgumentException if the arrays have different sizes
  447.      * @see SwitchTransformer
  448.      */
  449.     public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
  450.             final Transformer<? super I, ? extends O>[] transformers,
  451.             final Transformer<? super I, ? extends O> defaultTransformer) {
  452.         return SwitchTransformer.switchTransformer(predicates, transformers, defaultTransformer);
  453.     }

  454.     /**
  455.      * This class is not normally instantiated.
  456.      */
  457.     private TransformerUtils() {
  458.         // empty
  459.     }

  460. }