View Javadoc
1   /*
2    * Copyright 2007 Kasper B. Graversen
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.supercsv.cellprocessor;
17  
18  import java.util.Collections;
19  import java.util.HashSet;
20  import java.util.Set;
21  
22  import org.supercsv.cellprocessor.ift.BoolCellProcessor;
23  import org.supercsv.cellprocessor.ift.StringCellProcessor;
24  import org.supercsv.exception.SuperCsvCellProcessorException;
25  import org.supercsv.util.CsvContext;
26  
27  /**
28   * Converts a String to a Boolean.
29   * <p>
30   * The default values for true are: <tt>"true", "1", "y", "t"</tt>
31   * <p>
32   * The default values for false are: <tt>"false", "0", "n", "f"</tt>
33   * <p>
34   * By default (unless the <tt>ignoreCase</tt> parameter is supplied on the constructor) this processor will ignore the
35   * case of the value, i.e. "true", "TRUE", and "True" will all be converted to <tt>true</tt> (likewise for
36   * <tt>false</tt>).
37   * <p>
38   * Prior to version 2.2.1, this processor always ignored case, so it was necessary to ensure that all supplied
39   * true/false values were lowercase, as the input was converted to lowercase before comparison against the true/false
40   * values (to handle all variations of case in the input). This is no longer required (just use the <tt>ignoreCase</tt>
41   * parameter).
42   * 
43   * @author Kasper B. Graversen
44   * @author Dominique De Vito
45   * @author James Bassett
46   * @since 1.0
47   */
48  public class ParseBool extends CellProcessorAdaptor implements StringCellProcessor {
49  	
50  	private static final String[] DEFAULT_TRUE_VALUES = new String[] { "1", "true", "t", "y" };
51  	private static final String[] DEFAULT_FALSE_VALUES = new String[] { "0", "false", "f", "n" };
52  	
53  	private final Set<String> trueValues = new HashSet<String>();
54  	private final Set<String> falseValues = new HashSet<String>();
55  	
56  	private final boolean ignoreCase;
57  	
58  	/**
59  	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the default values
60  	 * (ignoring case).
61  	 */
62  	public ParseBool() {
63  		this(DEFAULT_TRUE_VALUES, DEFAULT_FALSE_VALUES);
64  	}
65  	
66  	/**
67  	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the default values
68  	 * (ignoring case if desired).
69  	 * 
70  	 * @since 2.2.1
71  	 * @param ignoreCase
72  	 *            whether to ignore the case when comparing against the true/false values
73  	 */
74  	public ParseBool(final boolean ignoreCase) {
75  		this(DEFAULT_TRUE_VALUES, DEFAULT_FALSE_VALUES, ignoreCase);
76  	}
77  	
78  	/**
79  	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the default values
80  	 * (ignoring case), then calls the next processor in the chain.
81  	 * 
82  	 * @param next
83  	 *            the next processor in the chain
84  	 * @throws NullPointerException
85  	 *             if next is null
86  	 */
87  	public ParseBool(final BoolCellProcessor next) {
88  		this(DEFAULT_TRUE_VALUES, DEFAULT_FALSE_VALUES, next);
89  	}
90  	
91  	/**
92  	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the default values
93  	 * (ignoring case if desired), then calls the next processor in the chain.
94  	 * 
95  	 * @since 2.2.1
96  	 * @param ignoreCase
97  	 *            whether to ignore the case when comparing against the true/false values
98  	 * @param next
99  	 *            the next processor in the chain
100 	 * @throws NullPointerException
101 	 *             if next is null
102 	 */
103 	public ParseBool(final boolean ignoreCase, final BoolCellProcessor next) {
104 		this(DEFAULT_TRUE_VALUES, DEFAULT_FALSE_VALUES, ignoreCase, next);
105 	}
106 	
107 	/**
108 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
109 	 * values (ignoring case).
110 	 * 
111 	 * @param trueValue
112 	 *            the String which represents true
113 	 * @param falseValue
114 	 *            the String which represents false
115 	 * @throws NullPointerException
116 	 *             if trueValue or falseValue is null
117 	 */
118 	public ParseBool(final String trueValue, final String falseValue) {
119 		this(trueValue, falseValue, true);
120 	}
121 	
122 	/**
123 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
124 	 * values (ignoring case if desired).
125 	 * 
126 	 * @since 2.2.1
127 	 * @param trueValue
128 	 *            the String which represents true
129 	 * @param falseValue
130 	 *            the String which represents false
131 	 * @param ignoreCase
132 	 *            whether to ignore the case when comparing against the true/false values
133 	 * @throws NullPointerException
134 	 *             if trueValue or falseValue is null
135 	 */
136 	public ParseBool(final String trueValue, final String falseValue, final boolean ignoreCase) {
137 		super();
138 		checkPreconditions(trueValue, falseValue);
139 		trueValues.add(trueValue);
140 		falseValues.add(falseValue);
141 		this.ignoreCase = ignoreCase;
142 	}
143 	
144 	/**
145 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
146 	 * values (ignoring case).
147 	 * 
148 	 * @param trueValues
149 	 *            the array of Strings which represent true
150 	 * @param falseValues
151 	 *            the array of Strings which represent false
152 	 * @throws IllegalArgumentException
153 	 *             if trueValues or falseValues is empty
154 	 * @throws NullPointerException
155 	 *             if trueValues or falseValues is null
156 	 */
157 	public ParseBool(final String[] trueValues, final String[] falseValues) {
158 		this(trueValues, falseValues, true);
159 	}
160 	
161 	/**
162 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
163 	 * values (ignoring case if desired).
164 	 * 
165 	 * @since 2.2.1
166 	 * @param trueValues
167 	 *            the array of Strings which represent true
168 	 * @param falseValues
169 	 *            the array of Strings which represent false
170 	 * @param ignoreCase
171 	 *            whether to ignore the case when comparing against the true/false values
172 	 * @throws IllegalArgumentException
173 	 *             if trueValues or falseValues is empty
174 	 * @throws NullPointerException
175 	 *             if trueValues or falseValues is null
176 	 */
177 	public ParseBool(final String[] trueValues, final String[] falseValues, final boolean ignoreCase) {
178 		super();
179 		checkPreconditions(trueValues, falseValues);
180 		Collections.addAll(this.trueValues, trueValues);
181 		Collections.addAll(this.falseValues, falseValues);
182 		this.ignoreCase = ignoreCase;
183 	}
184 	
185 	/**
186 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
187 	 * values (ignoring case), then calls the next processor in the chain.
188 	 * 
189 	 * @param trueValue
190 	 *            the String which represents true
191 	 * @param falseValue
192 	 *            the String which represents false
193 	 * @param next
194 	 *            the next processor in the chain
195 	 * @throws NullPointerException
196 	 *             if trueValue, falseValue or next is null
197 	 */
198 	public ParseBool(final String trueValue, final String falseValue, final BoolCellProcessor next) {
199 		this(trueValue, falseValue, true, next);
200 	}
201 	
202 	/**
203 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
204 	 * values (ignoring case if desired), then calls the next processor in the chain.
205 	 * 
206 	 * @since 2.2.1
207 	 * @param trueValue
208 	 *            the String which represents true
209 	 * @param falseValue
210 	 *            the String which represents false
211 	 * @param ignoreCase
212 	 *            whether to ignore the case when comparing against the true/false values
213 	 * @param next
214 	 *            the next processor in the chain
215 	 * @throws NullPointerException
216 	 *             if trueValue, falseValue or next is null
217 	 */
218 	public ParseBool(final String trueValue, final String falseValue, final boolean ignoreCase,
219 		final BoolCellProcessor next) {
220 		super(next);
221 		checkPreconditions(trueValue, falseValue);
222 		trueValues.add(trueValue);
223 		falseValues.add(falseValue);
224 		this.ignoreCase = ignoreCase;
225 	}
226 	
227 	/**
228 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
229 	 * values (ignoring case), then calls the next processor in the chain.
230 	 * 
231 	 * @param trueValues
232 	 *            the array of Strings which represent true
233 	 * @param falseValues
234 	 *            the array of Strings which represent false
235 	 * @param next
236 	 *            the next processor in the chain
237 	 * @throws IllegalArgumentException
238 	 *             if trueValues or falseValues is empty
239 	 * @throws NullPointerException
240 	 *             if trueValues, falseValues, or next is null
241 	 */
242 	public ParseBool(final String[] trueValues, final String[] falseValues, final BoolCellProcessor next) {
243 		this(trueValues, falseValues, true, next);
244 	}
245 	
246 	/**
247 	 * Constructs a new <tt>ParseBool</tt> processor, which converts a String to a Boolean using the supplied true/false
248 	 * values (ignoring case if desired), then calls the next processor in the chain.
249 	 * 
250 	 * @since 2.2.1
251 	 * @param trueValues
252 	 *            the array of Strings which represent true
253 	 * @param falseValues
254 	 *            the array of Strings which represent false
255 	 * @param ignoreCase
256 	 *            whether to ignore the case when comparing against the true/false values
257 	 * @param next
258 	 *            the next processor in the chain
259 	 * @throws IllegalArgumentException
260 	 *             if trueValues or falseValues is empty
261 	 * @throws NullPointerException
262 	 *             if trueValues, falseValues, or next is null
263 	 */
264 	public ParseBool(final String[] trueValues, final String[] falseValues, final boolean ignoreCase,
265 		final BoolCellProcessor next) {
266 		super(next);
267 		checkPreconditions(trueValues, falseValues);
268 		Collections.addAll(this.trueValues, trueValues);
269 		Collections.addAll(this.falseValues, falseValues);
270 		this.ignoreCase = ignoreCase;
271 	}
272 	
273 	/**
274 	 * Checks the preconditions for constructing a new ParseBool processor.
275 	 * 
276 	 * @param trueValue
277 	 *            the String which represents true
278 	 * @param falseValue
279 	 *            the String which represents false
280 	 * @throws NullPointerException
281 	 *             if trueValue or falseValue is null
282 	 */
283 	private static void checkPreconditions(final String trueValue, final String falseValue) {
284 		if( trueValue == null ) {
285 			throw new NullPointerException("trueValue should not be null");
286 		}
287 		if( falseValue == null ) {
288 			throw new NullPointerException("falseValue should not be null");
289 		}
290 	}
291 	
292 	/**
293 	 * Checks the preconditions for constructing a new ParseBool processor.
294 	 * 
295 	 * @param trueValues
296 	 *            the array of Strings which represent true
297 	 * @param falseValues
298 	 *            the array of Strings which represent false
299 	 * @throws IllegalArgumentException
300 	 *             if trueValues or falseValues is empty
301 	 * @throws NullPointerException
302 	 *             if trueValues or falseValues is null
303 	 */
304 	private static void checkPreconditions(final String[] trueValues, final String[] falseValues) {
305 		
306 		if( trueValues == null ) {
307 			throw new NullPointerException("trueValues should not be null");
308 		} else if( trueValues.length == 0 ) {
309 			throw new IllegalArgumentException("trueValues should not be empty");
310 		}
311 		
312 		if( falseValues == null ) {
313 			throw new NullPointerException("falseValues should not be null");
314 		} else if( falseValues.length == 0 ) {
315 			throw new IllegalArgumentException("falseValues should not be empty");
316 		}
317 		
318 	}
319 	
320 	/**
321 	 * {@inheritDoc}
322 	 * 
323 	 * @throws SuperCsvCellProcessorException
324 	 *             if value is null, not a String, or can't be parsed to a Boolean
325 	 */
326 	public Object execute(final Object value, final CsvContext context) {
327 		validateInputNotNull(value, context);
328 		
329 		if( !(value instanceof String) ) {
330 			throw new SuperCsvCellProcessorException(String.class, value, context, this);
331 		}
332 		
333 		final String stringValue = (String) value;
334 		final Boolean result;
335 		if( contains(trueValues, stringValue, ignoreCase) ) {
336 			result = Boolean.TRUE;
337 		} else if( contains(falseValues, stringValue, ignoreCase) ) {
338 			result = Boolean.FALSE;
339 		} else {
340 			throw new SuperCsvCellProcessorException(String.format("'%s' could not be parsed as a Boolean", value),
341 				context, this);
342 		}
343 		
344 		return next.execute(result, context);
345 	}
346 	
347 	/**
348 	 * Returns true if the set contains the value, otherwise false.
349 	 * 
350 	 * @param set
351 	 *            the set
352 	 * @param value
353 	 *            the value to find
354 	 * @param ignoreCase
355 	 *            whether to ignore case
356 	 * @return true if the set contains the value, otherwise false
357 	 */
358 	private static boolean contains(Set<String> set, String value, boolean ignoreCase) {
359 		if( ignoreCase ) {
360 			for( String element : set ) {
361 				if( element.equalsIgnoreCase(value) ) {
362 					return true;
363 				}
364 			}
365 			return false;
366 			
367 		} else {
368 			return set.contains(value);
369 		}
370 	}
371 	
372 }