    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.commons.util;
    014
    015import java.util.Map;
    016
    017import org.apache.tapestry5.commons.services.Coercion;
    018
    019/**
    020 * A {@link org.apache.tapestry5.commons.services.Coercion} for converting strings into an instance of a particular
    021 * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
    022 * fashion.
    023 *
    024 * Moved from tapestry-core to tapestry-ioc in release 5.3, but kept in same package for compatibility.
    025 * Moved tapestry-ioc to commons in release 5.4, but kept in same package for compatibility.
    026 *
    027 * @param <T>
    028 *            the type of enumeration
    029 */
    030public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
    031{
    032    private final Class<T> enumClass;
    033
    034    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
    035
    036    public StringToEnumCoercion(Class<T> enumClass)
    037    {
    038        this(enumClass, enumClass.getEnumConstants());
    039    }
    040
    041    public StringToEnumCoercion(Class<T> enumClass, T... values)
    042    {
    043        this.enumClass = enumClass;
    044
    045        for (T value : values)
    046            stringToEnum.put(value.name(), value);
    047    }
    048
    049    @Override
    050    public T coerce(String input)
    051    {
    052        if (CommonsUtils.isBlank(input))
    053            return null;
    054
    055        T result = stringToEnum.get(input);
    056
    057        if (result == null)
    058        {
    059            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
    060                    enumClass.getName());
    061
    062            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
    063                    stringToEnum));
    064        }
    065
    066        return result;
    067    }
    068
    069    /**
    070     * Allows an alias value (alternate) string to reference a value.
    071     *
    072     * @since 5.2.2
    073     */
    074    public StringToEnumCoercion<T> addAlias(String alias, T value)
    075    {
    076        stringToEnum.put(alias, value);
    077
    078        return this;
    079    }
    080
    081    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
    082    {
    083        return new StringToEnumCoercion<T>(enumClass);
    084    }
    085
    086}