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