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 }