Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
package org.apache.commons.beanutils2.converters;

import java.text.Collator;
import java.util.Locale;

/**
* {@link org.apache.commons.beanutils2.Converter} implementation that handles conversion to and from <strong>Boolean</strong> objects.
* {@link org.apache.commons.beanutils2.Converter} implementation that handles conversion to and from {@link Boolean} objects.
Expand Down Expand Up @@ -43,20 +46,6 @@
*/
public final class BooleanConverter extends AbstractConverter<Boolean> {

/**
* Copies the provided array, and ensures that all the strings in the newly created array contain only lower-case letters.
* <p>
* Using this method to copy string arrays means that changes to the src array do not modify the dst array.
* </p>
*/
private static String[] copyStrings(final String[] src) {
final String[] dst = new String[src.length];
for (int i = 0; i < src.length; ++i) {
dst[i] = toLowerCase(src[i]);
}
return dst;
}

/**
* The set of strings that are known to map to Boolean.TRUE.
*/
Expand All @@ -67,6 +56,11 @@ private static String[] copyStrings(final String[] src) {
*/
private String[] falseStrings = { "false", "no", "n", "off", "0" };

/**
* The locale to use for string comparisons.
*/
private Locale locale = Locale.ROOT;

/**
* Constructs a {@link org.apache.commons.beanutils2.Converter} that will throw a {@link org.apache.commons.beanutils2.ConversionException} if a conversion
* error occurs, that is, if the string value being converted is not one of the known true strings, nor one of the known false strings.
Expand Down Expand Up @@ -97,8 +91,8 @@ public BooleanConverter(final Boolean defaultValue) {
* @since 1.8.0
*/
public BooleanConverter(final String[] trueStrings, final String[] falseStrings) {
this.trueStrings = copyStrings(trueStrings);
this.falseStrings = copyStrings(falseStrings);
this.trueStrings = trueStrings.clone();
this.falseStrings = falseStrings.clone();
}

/**
Expand All @@ -115,8 +109,26 @@ public BooleanConverter(final String[] trueStrings, final String[] falseStrings)
*/
public BooleanConverter(final String[] trueStrings, final String[] falseStrings, final Boolean defaultValue) {
super(defaultValue);
this.trueStrings = copyStrings(trueStrings);
this.falseStrings = copyStrings(falseStrings);
this.trueStrings = trueStrings.clone();
this.falseStrings = falseStrings.clone();
}

/**
* Get the locale used for string comparisons.
*
* @return The locale used for string comparisons.
*/
public Locale getLocale() {
return locale;
}

/**
* Set the locale used for string comparisons.
*
* @param locale The locale used for string comparisons.
*/
public void setLocale(Locale locale) {
this.locale = locale;
}

/**
Expand All @@ -136,20 +148,18 @@ public BooleanConverter(final String[] trueStrings, final String[] falseStrings,
@Override
protected <T> T convertToType(final Class<T> type, final Object value) throws Throwable {
if (Boolean.class.equals(type) || Boolean.TYPE.equals(type)) {
// All the values in the trueStrings and falseStrings arrays are
// guaranteed to be lower-case. By converting the input value
// to lowercase too, we can use the efficient String.equals method
// instead of the less-efficient String.equalsIgnoreCase method.
final String stringValue = toLowerCase(value);
final String stringValue = toString(value);
Collator collator = Collator.getInstance(locale);
collator.setStrength(Collator.SECONDARY);

for (final String trueString : trueStrings) {
if (trueString.equals(stringValue)) {
if (collator.equals(trueString, stringValue)) {
return type.cast(Boolean.TRUE);
}
}

for (final String falseString : falseStrings) {
if (falseString.equals(stringValue)) {
if (collator.equals(falseString, stringValue)) {
return type.cast(Boolean.FALSE);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Locale;

import org.apache.commons.beanutils2.ConversionException;
import org.junit.jupiter.api.Test;

Expand All @@ -44,6 +46,26 @@ void testAdditionalStrings() {
assertThrows(ConversionException.class, () -> converter.convert(Boolean.class, "bogus"));
}

@Test
void testAdditionalStringsLocale() {
final String[] trueStrings = { "\u03BD\u03B1\u03B9" }; // ναι
final String[] falseStrings = { "hay\u0131r" }; // hayır
final BooleanConverter converter = new BooleanConverter(trueStrings, falseStrings);

converter.setLocale(Locale.forLanguageTag("el"));
// "ναι" and "ΝΑΙ"
for (final String trueValue : new String[] { "\u03BD\u03B1\u03B9", "\u039D\u0391\u0399" }) {
assertEquals(Boolean.TRUE, converter.convert(Boolean.class, trueValue));
}

converter.setLocale(Locale.forLanguageTag("tr"));
// "hayır" and "HAYIR"
for (final String falseValue : new String[] { "hay\u0131r", "Hayır" }) {
assertEquals(Boolean.FALSE, converter.convert(Boolean.class, falseValue));
}
assertThrows(ConversionException.class, () -> converter.convert(Boolean.class, "hayir"));
}

@Test
void testCaseInsensitivity() {
final AbstractConverter<Boolean> converter = new BooleanConverter();
Expand Down
Loading