1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.collections15.functors.transformer;
17
18 import net.sf.collections15.Closure;
19 import net.sf.collections15.Factory;
20 import net.sf.collections15.Predicate;
21 import net.sf.collections15.Transformer;
22 import net.sf.collections15.functors.predicate.EqualPredicate;
23
24 import java.util.HashMap;
25 import java.util.Map;
26
27 /***
28 * <code>TransformerUtils</code> provides reference implementations and
29 * utilities for the {@link Transformer} functor interface. The supplied
30 * <code>Transformer</code>s are: <ul> <li>Invoker - returns the result of a
31 * method call on the input object <li>Clone - returns a clone of the input
32 * object <li>Constant - always returns the same object <li>Closure - performs a
33 * Closure and returns the input object <li>Predicate - returns the result of
34 * the predicate as a Boolean <li>Factory - returns a new object from a factory
35 * <li>Chained - chains two or more transformers together <li>Switch - calls one
36 * transformer based on one or more predicates <li>SwitchMap - calls one
37 * transformer looked up from a Map <li>Instantiate - the Class input object is
38 * instantiated <li>Map - returns an object from a supplied Map <li>Null -
39 * always returns null <li>NOP - returns the input object, which should be
40 * immutable <li>Exception - always throws an exception <li>StringValue -
41 * returns a <code>java.lang.String</code> representation of the input object
42 * </ul> All the supplied <code>Transformer</code>s are Serializable.
43 *
44 * @author Stephen Colebourne
45 * @author James Carman
46 * @author Chris Lambrou (port to Java 5.0)
47 * @since Collections15 1.0
48 */
49 public class TransformerUtils
50 {
51
52 /***
53 * Protected constructor prevents direct instantiation, but allows users to
54 * extend this library to provide their own augmented static library class.
55 */
56 protected TransformerUtils()
57 {
58 }
59
60 /***
61 * Returns a <code>Transformer</code> that always throws an exception. This
62 * could be useful during testing as a placeholder.
63 *
64 * @return A <code>Transformer</code> that always throws an exception.
65 *
66 * @see ExceptionTransformer
67 */
68 public static <I, O> Transformer<I, O> exceptionTransformer()
69 {
70 return ExceptionTransformer.getInstance();
71 }
72
73 /***
74 * Returns a <code>Transformer</code> that always returns
75 * <code>null</code>.
76 *
77 * @return A <code>Transformer</code> that always returns
78 * <code>null</code>.
79 *
80 * @see ConstantTransformer
81 */
82 public static <I, O> Transformer<I, O> nullTransformer()
83 {
84 return ConstantTransformer.getInstance(null);
85 }
86
87 /***
88 * Returns a <code>Transformer</code> that simply returns the input object.
89 * The input object should be immutable to maintain the contract of
90 * <code>Transformer</code> (although this is not checked).
91 *
92 * @return A <code>Transformer</code> that simply returns the input object.
93 *
94 * @see NOPTransformer
95 */
96 public static <T> Transformer<T, T> nopTransformer()
97 {
98 return NOPTransformer.getInstance();
99 }
100
101 /***
102 * Returns a <code>Transformer</code> that returns a clone of the input
103 * object. The input object will be cloned using one of these techniques (in
104 * order): <ul> <li>public clone method</li> <li>public copy
105 * constructor</li> <li>serialization clone <ul>
106 *
107 * @return A <code>Transformer</code> that returns a clone of the input
108 * object.
109 *
110 * @see CloneTransformer
111 */
112 public static <T> Transformer<T, T> cloneTransformer()
113 {
114 return CloneTransformer.getInstance();
115 }
116
117 /***
118 * Returns a <code>Transformer</code> that returns the same object each time
119 * the transformer is used.
120 *
121 * @param constantToReturn The constant object to be returned by the
122 * <code>Transformer</code>'s <code>transform</code>
123 * method.
124 *
125 * @return A <code>Transformer</code> that returns the same object each time
126 * the transformer is used.
127 *
128 * @see ConstantTransformer
129 */
130 public static <I, O> Transformer<I, O> constantTransformer(O constantToReturn)
131 {
132 return ConstantTransformer.getInstance(constantToReturn);
133 }
134
135 /***
136 * Returns a <code>Transformer</code> that executes a <code>Closure</code>
137 * on the input, before returning it as output.
138 *
139 * @param closure The <code>Closure</code> to execute in the transform.
140 *
141 * @return A <code>Transformer</code> that executes a <code>Closure</code>
142 * on the input, before returning it as output.
143 *
144 * @throws IllegalArgumentException Throws if the <code>Closure</code> is
145 * <code>null</code>.
146 * @see ClosureTransformer
147 */
148 public static <T> Transformer<T, T> asTransformer(Closure<T> closure)
149 {
150 return ClosureTransformer.getInstance(closure);
151 }
152
153 /***
154 * Returns a <code>Transformer</code> that evaluates a
155 * <code>Predicate</code> each time the <code>Transformer</code> is used,
156 * with the result of the <code>Predicate</code> returned as output.
157 *
158 * @param predicate The <code>Predicate</code> to execute in the transform.
159 *
160 * @return A <code>Transformer</code> that evaluates a <code>Predicate</code>
161 * each time the <code>Transformer</code> is used, with the result
162 * of the <code>Predicate</code> returned as output.
163 *
164 * @throws IllegalArgumentException Thrown if the <code>Predicate</code> is
165 * <code>null</code>.
166 * @see PredicateTransformer
167 */
168 public static <T> Transformer<T, Boolean> asTransformer(Predicate<T> predicate)
169 {
170 return PredicateTransformer.getInstance(predicate);
171 }
172
173 /***
174 * Returns a <code>Transformer</code> implementation whose
175 * <code>transform</code> method uses a {@link Factory} to create the
176 * returned output object.
177 *
178 * @param factory The <code>factory</codd> used to create the transform
179 * output objects.
180 *
181 * @return A <code>Transformer</code> implementation whose
182 * <code>transform</code> method uses a {@link Factory} to create
183 * the returned output object.
184 *
185 * @throws IllegalArgumentException Thrown if the <code>Factory</code> is
186 * <code>null</code>.
187 * @see FactoryTransformer
188 */
189 public static <I, O> Transformer<I, O> asTransformer(Factory<O> factory)
190 {
191 return FactoryTransformer.getInstance(factory);
192 }
193
194 /***
195 * Returns a <code>Transformer</code> whose <code>transform</code> method
196 * chains together the <code>transform</code> methods of two existing
197 * <code>Transformer</code>s
198 * <p/>
199 * If you need to chain together more than two <code>Transformer</code>s,
200 * you can use {@link ChainedTransformer#getInstance} and the convenience
201 * methods {@link ChainedTransformer#append} and {@link
202 * ChainedTransformer#prepend} instead.
203 *
204 * @param transformer1 The first <code>Transformer</code>.
205 * @param transformer2 the second <code>Transformer</code>.
206 *
207 * @return A <code>Transformer</code> whose <code>transform</code> method
208 * chains together the <code>transform</code> methods of two
209 * existing <code>Transformer</code>s
210 *
211 * @throws IllegalArgumentException Thrown if either <code>Transformer</code>
212 * is <code>null</code>.
213 * @see ChainedTransformer
214 */
215 public static <I, M, O> Transformer<I, O> chainedTransformer(Transformer<? super I, ? extends M> transformer1,
216 Transformer<? super M, ? extends O> transformer2)
217 {
218 return ChainedTransformer.getInstance(transformer1, transformer2);
219 }
220
221 /***
222 * Returns a <code>Transformer</code> that delegates to one of two existing
223 * <code>Transformers</code>, depending on the result of a
224 * <code>Predicate</code>.
225 *
226 * @param predicate The <code>Predicate</code> evaluated to determine
227 * which of the <code>Transformer</code>s to
228 * delegate to.
229 * @param trueTransformer The <code>Transformer</code> used if the
230 * <code>Predicate</code> evaluates <code>true</code>.
231 * @param falseTransformer The <code>Transformer</code> used if the
232 * <code>Predicate</code> evaluates <code>false</code>.
233 *
234 * @return A <code>Transformer</code> that delegates to one of two existing
235 * <code>Transformers</code>, depending on the result of a
236 * <code>Predicate</code>.
237 *
238 * @throws IllegalArgumentException Thrown if any argument is <code>null</code>.
239 * @see SwitchTransformer
240 */
241 public static <I, O> Transformer<I, O> ifElseTransformer(Predicate<I> predicate, Transformer<I, O> trueTransformer, Transformer<I, O> falseTransformer)
242 {
243 Map<Predicate<I>, Transformer<I, O>> map = new HashMap<Predicate<I>, Transformer<I, O>>(3);
244 map.put(predicate, trueTransformer);
245 map.put(null, falseTransformer);
246 return SwitchTransformer.getInstance(map);
247 }
248
249 /***
250 * Returns a <code>Transformer</code> instance that uses the specified map
251 * of <code>Predicates</code> and <code>Transformer</code>s, delegating to
252 * the <code>Transformer</code> whose corresponding <code>Predicate</code>
253 * evaluates to <code>true</code>.
254 *
255 * @param predicatesAndTransformers A map of <code>Predicate</code>s to
256 * <code>Transformer</code>s. Each non-null
257 * <code>Predicate</code> key defines a
258 * single switch case, with the
259 * corresponding <code>Transformer</code>
260 * being used to transform an input object
261 * if it matches the <code>Predicate</code>.
262 * <p/>
263 * <code>Predicate</code>s are evaluated in
264 * the iteration order of the map's key
265 * set, with the exception of the
266 * <code>null Predicate</code> key. If a
267 * <code>null Predicate</code> key is
268 * specified in the set, it's corresponding
269 * <code>Transformer</code> is treated as
270 * the default case, used to transform an
271 * input object if it doesn't satisfy any
272 * of the non-<code>null Predicate</code>
273 * cases. If there is no default
274 * <code>Transformer</code>, an
275 * <code>IllegalArgumentException</code>
276 * will be thrown by the <code>transform</code>
277 * method.
278 * <p/>
279 * <b>Note that the map is not modified by
280 * this method</b>.
281 *
282 * @return A new instance that uses the specified map of
283 * <code>Predicates</code> and <code>Transformer</code>s.
284 *
285 * @throws IllegalArgumentException Thrown if the map is <code>null</code>.
286 * @throws IllegalArgumentException Thrown if any <code>Transformer</code>
287 * in the map is <code>null</code>.
288 */
289 public static <I, O> Transformer<I, O> switchTransformer(Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers)
290 {
291 return SwitchTransformer.getInstance(predicatesAndTransformers);
292 }
293
294 /***
295 * Returns a <code>Transformer</code> that uses the input object as a key to
296 * find the <code>Transformer</code> to delegate to.
297 *
298 * @param objectsAndTransformers A map consisting of object keys and
299 * <code>Transformer</code> values. The map is
300 * used to obtain a <code>Transformer</code>
301 * for an input object, which is then used to
302 * tansform the input object. If there is no
303 * matching <code>Transformer</code>, the
304 * default <code>Transformer</code> is used
305 * instead (specified in the map using a
306 * <code>null</code> key). If there is no
307 * default <code>Transformer</code>, an
308 * <code>IllegalArgumentException</code> will
309 * be thrown by the <code>transform</code>
310 * method.
311 *
312 * @return A <code>Transformer</code> that uses the input object as a key to
313 * find the <code>Transformer</code> to delegate to.
314 *
315 * @throws IllegalArgumentException Thrown if the map is <code>null</code>,
316 * empty, or any <code>Transformer</code>
317 * in the map is <code>null</code>.
318 * @see SwitchTransformer
319 */
320 public static <I, O> Transformer<I, O> switchMapTransformer(Map<I, Transformer<I, O>> objectsAndTransformers)
321 {
322 if (objectsAndTransformers == null) {
323 throw new IllegalArgumentException("The object and transformer map must not be null");
324 }
325 int size = (2 + (objectsAndTransformers.size() * 4)) / 3;
326 Map<Predicate<I>, Transformer<I, O>> map = new HashMap<Predicate<I>, Transformer<I, O>>(size);
327 for (Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
328 I key = entry.getKey();
329 Predicate<I> predicate = key == null ? null : EqualPredicate.getInstance(key);
330 map.put(predicate, entry.getValue());
331 }
332 return SwitchTransformer.getInstance(map);
333 }
334
335 /***
336 * Returns a <code>Transformer</code> that takes an input <code>Class</code>
337 * object and uses it to output an instance of that class, created by
338 * reflection using the parameterless constructor of the
339 * <code>Class</code>.
340 *
341 * @return A <code>Transformer</code> that takes an input <code>Class</code>
342 * object and uses it to output an instance of that class, created
343 * by reflection using the parameterless constructor of the
344 * <code>Class</code>.
345 *
346 * @see InstantiateTransformer
347 * @see InstantiateTransformer#transform
348 */
349 public static <T> Transformer<Class<? extends T>, T> instantiateTransformer()
350 {
351 return InstantiateTransformer.getInstance();
352 }
353
354 /***
355 * Returns a <code>Transformer</code> that takes an input <code>Class</code>
356 * object and uses it to output an instance of that class, created by
357 * reflection using the constructor of the <code>Class</code> specified by
358 * the <code>parameterTypes</code> argument, passing in the corresponding
359 * <code>arguments</code> to the constructor.
360 *
361 * @param parameterTypes The parameter types of the constructer to invoke on
362 * an input <code>Class</code>. May be
363 * <code>null</code> or empty if <code>arguments</code>
364 * is also <code>null</code> or empty, in which case
365 * the parameterless constructor will be used to
366 * create an output object from an input
367 * <code>Class</code>. The contents of this array are
368 * defensively copied.
369 * @param arguments The arguments to pass to the constructor invoked on
370 * an input <code>Class</code>.
371 *
372 * @return A <code>Transformer</code> that takes an input <code>Class</code>
373 * object and uses it to output an instance of that class, created
374 * by reflection using the constructor of the <code>Class</code>
375 * specified by the <code>parameterTypes</code> argument, passing in
376 * the corresponding <code>arguments</code> to the constructor.
377 *
378 * @throws IllegalArgumentException Thrown if either of <code>parameterTypes</code>
379 * or <code>arguments</code> is
380 * <code>null</code>, but the other is
381 * not.
382 * @throws IllegalArgumentException Thrown if any element in <code>parameterTypes</code>
383 * is <code>null</code>.
384 * @throws IllegalArgumentException Thrown if any none-<code>null</code>
385 * element in <code>arguments</code> is not
386 * an instance of its corresponding
387 * <code>parameterTypes</code> class.
388 * @see InstantiateTransformer
389 * @see InstantiateTransformer#transform
390 */
391 public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(Class[] parameterTypes, Object[] arguments)
392 {
393 return InstantiateTransformer.getInstance(parameterTypes, arguments);
394 }
395
396 /***
397 * Returns a <code>Transformer</code> that uses the specified map as a
398 * lookup to transform the input objects into the output objects.
399 *
400 * @param map The map used as a lookup to transform the input objects into
401 * output objects.
402 *
403 * @return A <code>Transformer</code> that uses the specified map as a
404 * lookup to transform the input objects into the output objects.
405 *
406 * @throws IllegalArgumentException if the map is <code>null</code>.
407 * @see MapTransformer
408 */
409 public static <I, O> Transformer<I, O> mapTransformer(Map<? extends I, ? extends O> map)
410 {
411 return MapTransformer.getInstance(map);
412 }
413
414 /***
415 * Returns a <code>Transformer</code> that invokes a specified method on the
416 * input object. The method must have no parameters.
417 * <p/>
418 * For example, <code>TransformerUtils.invokerTransformer("getName");</code>
419 * will call the <code>getName/code> method on the input object and output
420 * the return value.
421 * <p/>
422 * If a <code>null Class</code> is input to the <code>Transformer</code> it
423 * will throw an <code>IllegalArgumentException</code>.
424 *
425 * @param methodName the method name to call on the input object, may not be
426 * null. The return type of the method must be assignable
427 * to the generic type <code><O></code>
428 *
429 * @return A<code>Transformer</code> that invokes a specified method on the
430 * input object. The method must have no parameters.
431 *
432 * @throws IllegalArgumentException if <code>methodName</code> is null.
433 * @see InvokerTransformer
434 * @see InvokerTransformer#transform
435 */
436 public static <I, O> Transformer<I, O> invokerTransformer(String methodName)
437 {
438 return InvokerTransformer.getInstance(methodName, null, null);
439 }
440
441 /***
442 * Returns a <code>Transformer</code> that invokes a specified method on the
443 * input object.
444 *
445 * @param methodName the method name to call on the input object, may
446 * not be null. The return type of the method must be
447 * assignable to the generic type <code><O></code>
448 * @param parameterTypes The parameter types of the method to invoke on an
449 * input object. May be <code>null</code> or empty if
450 * <code>arguments</code> is also <code>null</code> or
451 * empty, in which case the parameterless mehod of the
452 * specified name will be used. The contents of this
453 * array are defensively copied.
454 * @param arguments The arguments to pass to the method invoked on an
455 * input <code>Class</code>.
456 *
457 * @return A <code>Transformer</code> that invokes a specified method on the
458 * input object.
459 *
460 * @throws IllegalArgumentException Thrown if the method name argument is
461 * <code>null</code>.
462 * @throws IllegalArgumentException Thrown if either of <code>parameterTypes</code>
463 * or <code>arguments</code> is
464 * <code>null</code>, but the other is
465 * not.
466 * @throws IllegalArgumentException Thrown if any element in <code>parameterTypes</code>
467 * is <code>null</code>.
468 * @throws IllegalArgumentException Thrown if any none-<code>null</code>
469 * element in <code>arguments</code> is not
470 * an instance of its corresponding
471 * <code>parameterTypes</code> class.
472 * @see InvokerTransformer
473 * @see InvokerTransformer#transform
474 */
475 public static <I, O> Transformer<I, O> invokerTransformer(String methodName, Class[] parameterTypes, Object[] arguments)
476 {
477 return InvokerTransformer.getInstance(methodName, parameterTypes, arguments);
478 }
479
480 /***
481 * Returns a <code>Transformer</code> that outputs the string value of the
482 * input, using the <code>String.valueOf</code> method. <code>null</code>
483 * returns 'null'.
484 *
485 * @return A <code>Transformer</code> that outputs the string value of the
486 * input, using the <code>String.valueOf</code> method.
487 *
488 * @see StringValueTransformer
489 */
490 public static <E> Transformer<E, String> stringValueTransformer()
491 {
492 return StringValueTransformer.getInstance();
493 }
494
495 }