Skip to content

Commit 53cd215

Browse files
author
Simon Kitching
committed
* Add facility for user to override the default set of true and false string definitions.
* provide NO_DEFAULT object that can be passed to constructors to indicate that no default object is desired. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/beanutils/trunk@156409 13f79535-47bb-0310-9956-ffa450edef68
1 parent 7e89470 commit 53cd215

File tree

1 file changed

+145
-41
lines changed

1 file changed

+145
-41
lines changed
Lines changed: 145 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2001-2004 The Apache Software Foundation.
2+
* Copyright 2001-2005 The Apache Software Foundation.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
1717

1818
package org.apache.commons.beanutils.converters;
1919

20-
2120
import org.apache.commons.beanutils.ConversionException;
2221
import org.apache.commons.beanutils.Converter;
2322

@@ -28,6 +27,27 @@
2827
* default value or throwing a {@link ConversionException} if a conversion
2928
* error occurs.</p>
3029
*
30+
* <p>By default any object whose string representation is one of the values
31+
* {"yes", "y", "true", "on", "1"} is converted to Boolean.TRUE, and
32+
* string representations {"no", "n", "false", "off", "0"} are converted
33+
* to Boolean.FALSE. The recognised true/false strings can be changed by:
34+
* <pre>
35+
* String[] trueStrings = {"oui", "o", "1"};
36+
* String[] falseStrings = {"non", "n", "0"};
37+
* Converter bc = new BooleanConverter(trueStrings, falseStrings);
38+
* ConvertUtils.register(bc, Boolean.class);
39+
* ConvertUtils.register(bc, Boolean.TYPE);
40+
* </pre>
41+
* In addition, it is recommended that the BooleanArrayConverter also be
42+
* modified to recognise the same set of values:
43+
* <pre>
44+
* Converter bac = new BooleanArrayConverter(bc, BooleanArrayConverter.NO_DEFAULT);
45+
* ConvertUtils.register(bac, bac.MODEL);
46+
* </pre>
47+
* </p>
48+
*
49+
* <p>Case is ignored when converting values to true or false.</p>
50+
*
3151
* @author Craig R. McClanahan
3252
* @version $Revision$ $Date$
3353
* @since 1.3
@@ -41,57 +61,133 @@ public final class BooleanConverter implements Converter {
4161

4262
/**
4363
* Create a {@link Converter} that will throw a {@link ConversionException}
44-
* if a conversion error occurs.
64+
* if a conversion error occurs, ie the string value being converted is
65+
* not one of the known true strings, nor one of the known false strings.
4566
*/
4667
public BooleanConverter() {
4768

48-
this.defaultValue = null;
4969
this.useDefault = false;
5070

5171
}
5272

5373

5474
/**
5575
* Create a {@link Converter} that will return the specified default value
56-
* if a conversion error occurs.
76+
* if a conversion error occurs, ie the string value being converted is
77+
* not one of the known true strings, nor one of the known false strings.
5778
*
58-
* @param defaultValue The default value to be returned
79+
* @param defaultValue The default value to be returned if the value
80+
* being converted is not recognised. This value may be null, in which
81+
* case null will be returned on conversion failure. When non-null, it is
82+
* expected that this value will be either Boolean.TRUE or Boolean.FALSE.
83+
* The special value BooleanConverter.NO_DEFAULT can also be passed here,
84+
* in which case this constructor acts like the no-argument one.
5985
*/
6086
public BooleanConverter(Object defaultValue) {
6187

62-
this.defaultValue = defaultValue;
63-
this.useDefault = true;
88+
if (defaultValue == NO_DEFAULT) {
89+
this.useDefault = false;
90+
} else {
91+
this.defaultValue = defaultValue;
92+
this.useDefault = true;
93+
}
94+
95+
}
96+
97+
/**
98+
* Create a {@link Converter} that will return the specified default value
99+
* if a conversion error occurs.
100+
* <p>
101+
* The provided string arrays are copied, so that changes to the elements
102+
* of the array after this call is made do not affect this object.
103+
*
104+
* @param trueStrings is the set of strings which should convert to the
105+
* value Boolean.TRUE. The value null must not be present. Case is
106+
* ignored.
107+
*
108+
* @param falseStrings is the set of strings which should convert to the
109+
* value Boolean.TRUE. The value null must not be present. Case is
110+
* ignored.
111+
*
112+
* @param defaultValue The default value to be returned if the value
113+
* being converted is not recognised. This value may be null, in which
114+
* case null will be returned on conversion failure. When non-null, it is
115+
* expected that this value will be either Boolean.TRUE or Boolean.FALSE.
116+
* The special value BooleanConverter.NO_DEFAULT can also be passed here,
117+
* in which case an exception will be thrown on conversion failure.
118+
*/
119+
public BooleanConverter(String[] trueStrings, String[] falseStrings,
120+
Object defaultValue) {
121+
122+
this.trueStrings = copyStrings(trueStrings);
123+
this.falseStrings = copyStrings(falseStrings);
124+
125+
if (defaultValue == NO_DEFAULT) {
126+
this.useDefault = false;
127+
} else {
128+
this.defaultValue = defaultValue;
129+
this.useDefault = true;
130+
}
64131

65132
}
66133

67134

135+
// ----------------------------------------------------- Static Variables
136+
137+
138+
/**
139+
* This is a special reference that can be passed as the "default object"
140+
* to the constructor to indicate that no default is desired. Note that
141+
* the value 'null' cannot be used for this purpose, as the caller may
142+
* want a null to be returned as the default.
143+
*/
144+
public static final Object NO_DEFAULT = new Object();
145+
146+
68147
// ----------------------------------------------------- Instance Variables
69148

70149

71150
/**
72151
* The default value specified to our Constructor, if any.
73152
*/
74-
private Object defaultValue = null;
75-
153+
private Object defaultValue;
76154

77155
/**
78156
* Should we return the default value on conversion errors?
79157
*/
80-
private boolean useDefault = true;
158+
private boolean useDefault;
81159

160+
/**
161+
* The set of strings that are known to map to Boolean.TRUE.
162+
*/
163+
private String[] trueStrings = {"yes", "y", "true", "on", "1"};
82164

83-
// --------------------------------------------------------- Public Methods
165+
/**
166+
* The set of strings that are known to map to Boolean.FALSE.
167+
*/
168+
private String[] falseStrings = {"no", "n", "false", "off", "0"};
84169

170+
// --------------------------------------------------------- Public Methods
85171

86172
/**
87173
* Convert the specified input object into an output object of the
88174
* specified type.
89175
*
90-
* @param type Data type to which this value should be converted
91-
* @param value The input value to be converted
176+
* @param type is the type to which this value should be converted. In the
177+
* case of this BooleanConverter class, this value is ignored.
178+
*
179+
* @param value is the input value to be converted. The toString method
180+
* shall be invoked on this object, and the result compared (ignoring
181+
* case) against the known "true" and "false" string values.
182+
*
183+
* @return Boolean.TRUE if the value was a recognised "true" value,
184+
* Boolean.FALSE if the value was a recognised "false" value, or
185+
* the default value if the value was not recognised and the constructor
186+
* was provided with a default value.
92187
*
93188
* @exception ConversionException if conversion cannot be performed
94-
* successfully
189+
* successfully and the constructor was not provided with a default
190+
* value to return on conversion failure.
95191
*/
96192
public Object convert(Class type, Object value) {
97193

@@ -107,34 +203,42 @@ public Object convert(Class type, Object value) {
107203
return (value);
108204
}
109205

110-
try {
111-
String stringValue = value.toString();
112-
if (stringValue.equalsIgnoreCase("yes") ||
113-
stringValue.equalsIgnoreCase("y") ||
114-
stringValue.equalsIgnoreCase("true") ||
115-
stringValue.equalsIgnoreCase("on") ||
116-
stringValue.equalsIgnoreCase("1")) {
117-
return (Boolean.TRUE);
118-
} else if (stringValue.equalsIgnoreCase("no") ||
119-
stringValue.equalsIgnoreCase("n") ||
120-
stringValue.equalsIgnoreCase("false") ||
121-
stringValue.equalsIgnoreCase("off") ||
122-
stringValue.equalsIgnoreCase("0")) {
123-
return (Boolean.FALSE);
124-
} else if (useDefault) {
125-
return (defaultValue);
126-
} else {
127-
throw new ConversionException(stringValue);
128-
}
129-
} catch (ClassCastException e) {
130-
if (useDefault) {
131-
return (defaultValue);
132-
} else {
133-
throw new ConversionException(e);
134-
}
206+
// All the values in the trueStrings and falseStrings arrays are
207+
// guaranteed to be lower-case. By converting the input value
208+
// to lowercase too, we can use the efficient String.equals method
209+
// instead of the less-efficient String.equalsIgnoreCase method.
210+
String stringValue = value.toString().toLowerCase();
211+
212+
for(int i=0; i<trueStrings.length; ++i) {
213+
if (trueStrings[i].equals(stringValue))
214+
return Boolean.TRUE;
135215
}
136216

137-
}
217+
for(int i=0; i<falseStrings.length; ++i) {
218+
if (falseStrings[i].equals(stringValue))
219+
return Boolean.FALSE;
220+
}
221+
222+
if (useDefault) {
223+
return defaultValue;
224+
}
138225

226+
throw new ConversionException(value.toString());
227+
}
139228

229+
/**
230+
* This method creates a copy of the provided array, and ensures that
231+
* all the strings in the newly created array contain only lower-case
232+
* letters.
233+
* <p>
234+
* Using this method to copy string arrays means that changes to the
235+
* src array do not modify the dst array.
236+
*/
237+
private static String[] copyStrings(String[] src) {
238+
String[] dst = new String[src.length];
239+
for(int i=0; i<src.length; ++i) {
240+
dst[i] = src[i].toLowerCase();
241+
}
242+
return dst;
243+
}
140244
}

0 commit comments

Comments
 (0)