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 */ 031public class SwitchTransformer<I, O> implements Transformer<I, O>, Serializable { 032 033 /** Serial version UID */ 034 private static final long serialVersionUID = -6404460890903469332L; 035 036 /** The tests to consider */ 037 private final Predicate<? super I>[] iPredicates; 038 /** The matching transformers to call */ 039 private final Transformer<? super I, ? extends O>[] iTransformers; 040 /** The default transformer to call if no tests match */ 041 private final Transformer<? super I, ? extends O> iDefault; 042 043 /** 044 * Factory method that performs validation and copies the parameter arrays. 045 * 046 * @param <I> the input type 047 * @param <O> the output type 048 * @param predicates array of predicates, cloned, no nulls 049 * @param transformers matching array of transformers, cloned, no nulls 050 * @param defaultTransformer the transformer to use if no match, null means return null 051 * @return the <code>chained</code> transformer 052 * @throws NullPointerException if array is null 053 * @throws NullPointerException if any element in the array is null 054 */ 055 @SuppressWarnings("unchecked") 056 public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates, 057 final Transformer<? super I, ? extends O>[] transformers, 058 final Transformer<? super I, ? extends O> defaultTransformer) { 059 FunctorUtils.validate(predicates); 060 FunctorUtils.validate(transformers); 061 if (predicates.length != transformers.length) { 062 throw new IllegalArgumentException("The predicate and transformer arrays must be the same size"); 063 } 064 if (predicates.length == 0) { 065 return (Transformer<I, O>) (defaultTransformer == null ? ConstantTransformer.<I, O>nullTransformer() : 066 defaultTransformer); 067 } 068 return new SwitchTransformer<>(predicates, transformers, defaultTransformer); 069 } 070 071 /** 072 * Create a new Transformer that calls one of the transformers depending 073 * on the predicates. 074 * <p> 075 * The Map consists of Predicate keys and Transformer values. A transformer 076 * is called if its matching predicate returns true. Each predicate is evaluated 077 * until one returns true. If no predicates evaluate to true, the default 078 * transformer is called. The default transformer is set in the map with a 079 * null key. The ordering is that of the iterator() method on the entryset 080 * collection of the map. 081 * 082 * @param <I> the input type 083 * @param <O> the output type 084 * @param map a map of predicates to transformers 085 * @return the <code>switch</code> transformer 086 * @throws NullPointerException if the map is null 087 * @throws NullPointerException if any transformer in the map is null 088 * @throws ClassCastException if the map elements are of the wrong type 089 */ 090 @SuppressWarnings("unchecked") 091 public static <I, O> Transformer<I, O> switchTransformer( 092 final Map<? extends Predicate<? super I>, ? extends Transformer<? super I, ? extends O>> map) { 093 094 if (map == null) { 095 throw new NullPointerException("The predicate and transformer map must not be null"); 096 } 097 if (map.size() == 0) { 098 return ConstantTransformer.<I, O>nullTransformer(); 099 } 100 // convert to array like this to guarantee iterator() ordering 101 final Transformer<? super I, ? extends O> defaultTransformer = map.remove(null); 102 final int size = map.size(); 103 if (size == 0) { 104 return (Transformer<I, O>) (defaultTransformer == null ? ConstantTransformer.<I, O>nullTransformer() : 105 defaultTransformer); 106 } 107 final Transformer<? super I, ? extends O>[] transformers = new Transformer[size]; 108 final Predicate<? super I>[] preds = new Predicate[size]; 109 int i = 0; 110 for (final Map.Entry<? extends Predicate<? super I>, 111 ? extends Transformer<? super I, ? extends O>> entry : map.entrySet()) { 112 preds[i] = entry.getKey(); 113 transformers[i] = entry.getValue(); 114 i++; 115 } 116 return new SwitchTransformer<>(false, preds, transformers, defaultTransformer); 117 } 118 119 /** 120 * Hidden constructor for the use by the static factory methods. 121 * 122 * @param clone if {@code true} the input arguments will be cloned 123 * @param predicates array of predicates, no nulls 124 * @param transformers matching array of transformers, no nulls 125 * @param defaultTransformer the transformer to use if no match, null means return null 126 */ 127 @SuppressWarnings("unchecked") 128 private SwitchTransformer(final boolean clone, final Predicate<? super I>[] predicates, 129 final Transformer<? super I, ? extends O>[] transformers, 130 final Transformer<? super I, ? extends O> defaultTransformer) { 131 super(); 132 iPredicates = clone ? FunctorUtils.copy(predicates) : predicates; 133 iTransformers = clone ? FunctorUtils.copy(transformers) : transformers; 134 iDefault = (Transformer<? super I, ? extends O>) (defaultTransformer == null ? 135 ConstantTransformer.<I, O>nullTransformer() : defaultTransformer); 136 } 137 138 /** 139 * Constructor that performs no validation. 140 * Use <code>switchTransformer</code> if you want that. 141 * 142 * @param predicates array of predicates, cloned, no nulls 143 * @param transformers matching array of transformers, cloned, no nulls 144 * @param defaultTransformer the transformer to use if no match, null means return null 145 */ 146 public SwitchTransformer(final Predicate<? super I>[] predicates, 147 final Transformer<? super I, ? extends O>[] transformers, 148 final Transformer<? super I, ? extends O> defaultTransformer) { 149 this(true, predicates, transformers, defaultTransformer); 150 } 151 152 /** 153 * Transforms the input to result by calling the transformer whose matching 154 * predicate returns true. 155 * 156 * @param input the input object to transform 157 * @return the transformed result 158 */ 159 @Override 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}