001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.functors; 018 019import java.io.Serializable; 020import java.util.Map; 021 022import org.apache.commons.collections4.Predicate; 023import org.apache.commons.collections4.Transformer; 024 025/** 026 * Transformer implementation calls the transformer whose predicate returns true, 027 * like a switch statement. 028 * 029 * @since 3.0 030 * @version $Id: SwitchTransformer.html 972421 2015-11-14 20:00:04Z tn $ 031 */ 032public class SwitchTransformer<I, O> implements Transformer<I, O>, Serializable { 033 034 /** Serial version UID */ 035 private static final long serialVersionUID = -6404460890903469332L; 036 037 /** The tests to consider */ 038 private final Predicate<? super I>[] iPredicates; 039 /** The matching transformers to call */ 040 private final Transformer<? super I, ? extends O>[] iTransformers; 041 /** The default transformer to call if no tests match */ 042 private final Transformer<? super I, ? extends O> iDefault; 043 044 /** 045 * Factory method that performs validation and copies the parameter arrays. 046 * 047 * @param <I> the input type 048 * @param <O> the output type 049 * @param predicates array of predicates, cloned, no nulls 050 * @param transformers matching array of transformers, cloned, no nulls 051 * @param defaultTransformer the transformer to use if no match, null means return null 052 * @return the <code>chained</code> transformer 053 * @throws IllegalArgumentException if array is null 054 * @throws IllegalArgumentException if any element in the array is null 055 */ 056 @SuppressWarnings("unchecked") 057 public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates, 058 final Transformer<? super I, ? extends O>[] transformers, 059 final Transformer<? super I, ? extends O> defaultTransformer) { 060 FunctorUtils.validate(predicates); 061 FunctorUtils.validate(transformers); 062 if (predicates.length != transformers.length) { 063 throw new IllegalArgumentException("The predicate and transformer arrays must be the same size"); 064 } 065 if (predicates.length == 0) { 066 return (Transformer<I, O>) (defaultTransformer == null ? ConstantTransformer.<I, O>nullTransformer() : 067 defaultTransformer); 068 } 069 return new SwitchTransformer<I, O>(predicates, transformers, defaultTransformer); 070 } 071 072 /** 073 * Create a new Transformer that calls one of the transformers depending 074 * on the predicates. 075 * <p> 076 * The Map consists of Predicate keys and Transformer values. A transformer 077 * is called if its matching predicate returns true. Each predicate is evaluated 078 * until one returns true. If no predicates evaluate to true, the default 079 * transformer is called. The default transformer is set in the map with a 080 * null key. The ordering is that of the iterator() method on the entryset 081 * collection of the map. 082 * 083 * @param <I> the input type 084 * @param <O> the output type 085 * @param map a map of predicates to transformers 086 * @return the <code>switch</code> transformer 087 * @throws IllegalArgumentException if the map is null 088 * @throws IllegalArgumentException if any transformer in the map is null 089 * @throws ClassCastException if the map elements are of the wrong type 090 */ 091 @SuppressWarnings("unchecked") 092 public static <I, O> Transformer<I, O> switchTransformer( 093 final Map<? extends Predicate<? super I>, ? extends Transformer<? super I, ? extends O>> map) { 094 095 if (map == null) { 096 throw new IllegalArgumentException("The predicate and transformer map must not be null"); 097 } 098 if (map.size() == 0) { 099 return ConstantTransformer.<I, O>nullTransformer(); 100 } 101 // convert to array like this to guarantee iterator() ordering 102 final Transformer<? super I, ? extends O> defaultTransformer = map.remove(null); 103 final int size = map.size(); 104 if (size == 0) { 105 return (Transformer<I, O>) (defaultTransformer == null ? ConstantTransformer.<I, O>nullTransformer() : 106 defaultTransformer); 107 } 108 final Transformer<? super I, ? extends O>[] transformers = new Transformer[size]; 109 final Predicate<? super I>[] preds = new Predicate[size]; 110 int i = 0; 111 for (final Map.Entry<? extends Predicate<? super I>, 112 ? extends Transformer<? super I, ? extends O>> entry : map.entrySet()) { 113 preds[i] = entry.getKey(); 114 transformers[i] = entry.getValue(); 115 i++; 116 } 117 return new SwitchTransformer<I, O>(false, preds, transformers, defaultTransformer); 118 } 119 120 /** 121 * Hidden constructor for the use by the static factory methods. 122 * 123 * @param clone if {@code true} the input arguments will be cloned 124 * @param predicates array of predicates, no nulls 125 * @param transformers matching array of transformers, no nulls 126 * @param defaultTransformer the transformer to use if no match, null means return null 127 */ 128 @SuppressWarnings("unchecked") 129 private SwitchTransformer(final boolean clone, final Predicate<? super I>[] predicates, 130 final Transformer<? super I, ? extends O>[] transformers, 131 final Transformer<? super I, ? extends O> defaultTransformer) { 132 super(); 133 iPredicates = clone ? FunctorUtils.copy(predicates) : predicates; 134 iTransformers = clone ? FunctorUtils.copy(transformers) : transformers; 135 iDefault = (Transformer<? super I, ? extends O>) (defaultTransformer == null ? 136 ConstantTransformer.<I, O>nullTransformer() : defaultTransformer); 137 } 138 139 /** 140 * Constructor that performs no validation. 141 * Use <code>switchTransformer</code> if you want that. 142 * 143 * @param predicates array of predicates, cloned, no nulls 144 * @param transformers matching array of transformers, cloned, no nulls 145 * @param defaultTransformer the transformer to use if no match, null means return null 146 */ 147 public SwitchTransformer(final Predicate<? super I>[] predicates, 148 final Transformer<? super I, ? extends O>[] transformers, 149 final Transformer<? super I, ? extends O> defaultTransformer) { 150 this(true, predicates, transformers, defaultTransformer); 151 } 152 153 /** 154 * Transforms the input to result by calling the transformer whose matching 155 * predicate returns true. 156 * 157 * @param input the input object to transform 158 * @return the transformed result 159 */ 160 public O transform(final I input) { 161 for (int i = 0; i < iPredicates.length; i++) { 162 if (iPredicates[i].evaluate(input) == true) { 163 return iTransformers[i].transform(input); 164 } 165 } 166 return iDefault.transform(input); 167 } 168 169 /** 170 * Gets the predicates. 171 * 172 * @return a copy of the predicates 173 * @since 3.1 174 */ 175 public Predicate<? super I>[] getPredicates() { 176 return FunctorUtils.<I>copy(iPredicates); 177 } 178 179 /** 180 * Gets the transformers. 181 * 182 * @return a copy of the transformers 183 * @since 3.1 184 */ 185 public Transformer<? super I, ? extends O>[] getTransformers() { 186 return FunctorUtils.<I, O>copy(iTransformers); 187 } 188 189 /** 190 * Gets the default transformer. 191 * 192 * @return the default transformer 193 * @since 3.1 194 */ 195 public Transformer<? super I, ? extends O> getDefaultTransformer() { 196 return iDefault; 197 } 198 199}