    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.beanutils2.converters;
    018
    019/**
    020 * {@link org.apache.commons.beanutils2.Converter} implementation that handles conversion to and from <strong>Boolean</strong> objects.
    021 * {@link org.apache.commons.beanutils2.Converter} implementation that handles conversion to and from {@link Boolean} objects.
    022 * <p>
    023 * Can be configured to either return a <em>default value</em> or throw a {@code ConversionException} if a conversion error occurs.
    024 * </p>
    025 * <p>
    026 * By default any object whose string representation is one of the values {"yes", "y", "true", "on", "1"} is converted to Boolean.TRUE, and string
    027 * representations {"no", "n", "false", "off", "0"} are converted to Boolean.FALSE. The recognized true/false strings can be changed by:
    028 * </p>
    029 *
    030 * <pre>
    031 * String[] trueStrings = { "oui", "o", "1" };
    032 * String[] falseStrings = { "non", "n", "0" };
    033 * Converter bc = new BooleanConverter(trueStrings, falseStrings);
    034 * ConvertUtils.register(bc, Boolean.class);
    035 * ConvertUtils.register(bc, Boolean.TYPE);
    036 * </pre>
    037 *
    038 * <p>
    039 * Case is ignored when converting values to true or false.
    040 * </p>
    041 *
    042 * @since 1.3
    043 */
    044public final class BooleanConverter extends AbstractConverter<Boolean> {
    045
    046    /**
    047     * Copies the provided array, and ensures that all the strings in the newly created array contain only lower-case letters.
    048     * <p>
    049     * Using this method to copy string arrays means that changes to the src array do not modify the dst array.
    050     * </p>
    051     */
    052    private static String[] copyStrings(final String[] src) {
    053        final String[] dst = new String[src.length];
    054        for (int i = 0; i < src.length; ++i) {
    055            dst[i] = toLowerCase(src[i]);
    056        }
    057        return dst;
    058    }
    059
    060    /**
    061     * The set of strings that are known to map to Boolean.TRUE.
    062     */
    063    private String[] trueStrings = { "true", "yes", "y", "on", "1" };
    064
    065    /**
    066     * The set of strings that are known to map to Boolean.FALSE.
    067     */
    068    private String[] falseStrings = { "false", "no", "n", "off", "0" };
    069
    070    /**
    071     * Constructs a {@link org.apache.commons.beanutils2.Converter} that will throw a {@link org.apache.commons.beanutils2.ConversionException} if a conversion
    072     * 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.
    073     */
    074    public BooleanConverter() {
    075    }
    076
    077    /**
    078     * Constructs a {@link org.apache.commons.beanutils2.Converter} that will return the specified default value if a conversion error occurs, that is, the
    079     * string value being converted is not one of the known true strings, nor one of the known false strings.
    080     *
    081     * @param defaultValue The default value to be returned if the value being converted is not recognized. This value may be null, in which case null will be
    082     *                     returned on conversion failure. When non-null, it is expected that this value will be either Boolean.TRUE or Boolean.FALSE. The
    083     *                     special value BooleanConverter.NO_DEFAULT can also be passed here, in which case this constructor acts like the no-argument one.
    084     */
    085    public BooleanConverter(final Boolean defaultValue) {
    086        super(defaultValue);
    087    }
    088
    089    /**
    090     * Constructs a {@link org.apache.commons.beanutils2.Converter} that will throw a {@link org.apache.commons.beanutils2.ConversionException} if a conversion
    091     * error occurs, that is, the string value being converted is not one of the known true strings, nor one of the known false strings.
    092     * <p>
    093     * The provided string arrays are copied, so that changes to the elements of the array after this call is made do not affect this object.
    094     *
    095     * @param trueStrings  is the set of strings which should convert to the value Boolean.TRUE. The value null must not be present. Case is ignored.
    096     * @param falseStrings is the set of strings which should convert to the value Boolean.TRUE. The value null must not be present. Case is ignored.
    097     * @since 1.8.0
    098     */
    099    public BooleanConverter(final String[] trueStrings, final String[] falseStrings) {
    100        this.trueStrings = copyStrings(trueStrings);
    101        this.falseStrings = copyStrings(falseStrings);
    102    }
    103
    104    /**
    105     * Constructs a {@link org.apache.commons.beanutils2.Converter} that will return the specified default value if a conversion error occurs.
    106     * <p>
    107     * The provided string arrays are copied, so that changes to the elements of the array after this call is made do not affect this object.
    108     *
    109     * @param trueStrings  is the set of strings which should convert to the value Boolean.TRUE. The value null must not be present. Case is ignored.
    110     * @param falseStrings is the set of strings which should convert to the value Boolean.TRUE. The value null must not be present. Case is ignored.
    111     * @param defaultValue The default value to be returned if the value being converted is not recognized. This value may be null, in which case null will be
    112     *                     returned on conversion failure. When non-null, it is expected that this value will be either Boolean.TRUE or Boolean.FALSE. The
    113     *                     special value BooleanConverter.NO_DEFAULT can also be passed here, in which case an exception will be thrown on conversion failure.
    114     * @since 1.8.0
    115     */
    116    public BooleanConverter(final String[] trueStrings, final String[] falseStrings, final Boolean defaultValue) {
    117        super(defaultValue);
    118        this.trueStrings = copyStrings(trueStrings);
    119        this.falseStrings = copyStrings(falseStrings);
    120    }
    121
    122    /**
    123     * Converts the specified input object into an output object of the specified type.
    124     *
    125     * @param <T>   Target type of the conversion.
    126     * @param type  is the type to which this value should be converted. In the case of this BooleanConverter class, this value is ignored.
    127     * @param value is the input value to be converted. The toString method shall be invoked on this object, and the result compared (ignoring case) against the
    128     *              known "true" and "false" string values.
    129     *
    130     * @return Boolean.TRUE if the value was a recognized "true" value, Boolean.FALSE if the value was a recognized "false" value, or the default value if the
    131     *         value was not recognized and the constructor was provided with a default value.
    132     *
    133     * @throws Throwable if an error occurs converting to the specified type
    134     * @since 1.8.0
    135     */
    136    @Override
    137    protected <T> T convertToType(final Class<T> type, final Object value) throws Throwable {
    138        if (Boolean.class.equals(type) || Boolean.TYPE.equals(type)) {
    139            // All the values in the trueStrings and falseStrings arrays are
    140            // guaranteed to be lower-case. By converting the input value
    141            // to lowercase too, we can use the efficient String.equals method
    142            // instead of the less-efficient String.equalsIgnoreCase method.
    143            final String stringValue = toLowerCase(value);
    144
    145            for (final String trueString : trueStrings) {
    146                if (trueString.equals(stringValue)) {
    147                    return type.cast(Boolean.TRUE);
    148                }
    149            }
    150
    151            for (final String falseString : falseStrings) {
    152                if (falseString.equals(stringValue)) {
    153                    return type.cast(Boolean.FALSE);
    154                }
    155            }
    156        }
    157
    158        throw conversionException(type, value);
    159    }
    160
    161    /**
    162     * Gets the default type this {@code Converter} handles.
    163     *
    164     * @return The default type this {@code Converter} handles.
    165     * @since 1.8.0
    166     */
    167    @Override
    168    protected Class<Boolean> getDefaultType() {
    169        return Boolean.class;
    170    }
    171}