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
19 import java.util.Collection;
20 import java.util.Map;
21 import java.util.Objects;
22
23 import org.apache.commons.collections4.functors.ChainedTransformer;
24 import org.apache.commons.collections4.functors.CloneTransformer;
25 import org.apache.commons.collections4.functors.ClosureTransformer;
26 import org.apache.commons.collections4.functors.ConstantTransformer;
27 import org.apache.commons.collections4.functors.EqualPredicate;
28 import org.apache.commons.collections4.functors.ExceptionTransformer;
29 import org.apache.commons.collections4.functors.FactoryTransformer;
30 import org.apache.commons.collections4.functors.IfTransformer;
31 import org.apache.commons.collections4.functors.InstantiateTransformer;
32 import org.apache.commons.collections4.functors.InvokerTransformer;
33 import org.apache.commons.collections4.functors.MapTransformer;
34 import org.apache.commons.collections4.functors.NOPTransformer;
35 import org.apache.commons.collections4.functors.PredicateTransformer;
36 import org.apache.commons.collections4.functors.StringValueTransformer;
37 import org.apache.commons.collections4.functors.SwitchTransformer;
38
39 /**
40 * {@code TransformerUtils} provides reference implementations and
41 * utilities for the Transformer functor interface. The supplied transformers are:
42 * <ul>
43 * <li>Invoker - returns the result of a method call on the input object
44 * <li>Clone - returns a clone of the input object
45 * <li>Constant - always returns the same object
46 * <li>Closure - performs a Closure and returns the input object
47 * <li>Predicate - returns the result of the predicate as a Boolean
48 * <li>Factory - returns a new object from a factory
49 * <li>Chained - chains two or more transformers together
50 * <li>If - calls one transformer or another based on a predicate
51 * <li>Switch - calls one transformer based on one or more predicates
52 * <li>SwitchMap - calls one transformer looked up from a Map
53 * <li>Instantiate - the Class input object is instantiated
54 * <li>Map - returns an object from a supplied Map
55 * <li>Null - always returns null
56 * <li>NOP - returns the input object, which should be immutable
57 * <li>Exception - always throws an exception
58 * <li>StringValue - returns a {@link String} representation of the input object
59 * </ul>
60 * <p>
61 * Since v4.1 only transformers which are considered to be safe are
62 * Serializable. Transformers considered to be unsafe for serialization are:
63 * </p>
64 * <ul>
65 * <li>Invoker
66 * <li>Clone
67 * <li>Instantiate
68 * </ul>
69 *
70 * @since 3.0
71 */
72 public class TransformerUtils {
73
74 /**
75 * Creates a Transformer that calls a Closure each time the transformer is used.
76 * The transformer returns the input object.
77 *
78 * @param <T> the input/output type
79 * @param closure the closure to run each time in the transformer, not null
80 * @return the transformer
81 * @throws NullPointerException if the closure is null
82 * @see ClosureTransformer
83 */
84 public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) {
85 return ClosureTransformer.closureTransformer(closure);
86 }
87
88 /**
89 * Creates a Transformer that calls a Factory each time the transformer is used.
90 * The transformer will return the value returned by the factory.
91 *
92 * @param <I> the input type
93 * @param <O> the output type
94 * @param factory the factory to run each time in the transformer, not null
95 * @return the transformer
96 * @throws NullPointerException if the factory is null
97 * @see FactoryTransformer
98 */
99 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 }