EnumConverter.java
package dev.orne.beans.converters;
/*-
* #%L
* Orne Beans
* %%
* Copyright (C) 2020 Orne Developments
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
import javax.validation.constraints.NotNull;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.converters.AbstractConverter;
import org.apache.commons.lang3.Validate;
import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
/**
* Implementation of {@code Converter} that converts {@code Enum} instances
* to and from {@code String} using value name as {@code String}
* representation.
*
* @author <a href="mailto:wamphiry@orne.dev">(w) Iker Hernaez</a>
* @version 2.1, 2022-10
* @since 0.1
*/
@API(status=Status.STABLE, since="0.1")
public class EnumConverter
extends AbstractConverter {
/**
* Shared instance that throws a {@code ConversionException} if an
* error occurs.
*/
public static final EnumConverter GENERIC = new EnumConverter();
/**
* Shared instance that returns {@code null} if an error occurs.
*/
public static final EnumConverter GENERIC_DEFAULT = new EnumConverter(null);
/**
* Creates a new generic instance that throws a {@code ConversionException} if an
* error occurs.
*/
private EnumConverter() {
super();
}
/**
* Creates a new generic instance that returns a default value if an error
* occurs.
*
* @param defaultValue The default value to be returned if the value to be
* converted is missing or an error occurs converting the value
*/
private EnumConverter(
final Enum<?> defaultValue) {
super(defaultValue);
}
/**
* {@inheritDoc}
*/
@Override
protected @NotNull Class<?> getDefaultType() {
return Enum.class;
}
/**
* {@inheritDoc}
*/
@Override
protected <T> T convertToType(
final @NotNull Class<T> type,
final Object value)
throws Throwable {
if (type.isEnum()) {
if (value == null) {
return null;
} else {
@SuppressWarnings("unchecked")
final Class<? extends Enum<?>> eType = (Class<? extends Enum<?>>) type;
return type.cast(enumFromName(eType, value.toString()));
}
}
throw conversionException(type, value);
}
/**
* Returns the enumeration constant of the specified type that matches the
* specified enumeration name.
*
* @param <T> The enumeration type
* @param type The enumeration type
* @param name The name of the constant
* @return The enumeration constant for the name
* @throws ConversionException If the type is not an enumeration or no
* constant matches the specified name
*/
protected <T> T enumFromName(
final @NotNull Class<T> type,
final @NotNull String name) {
Validate.notNull(type);
Validate.notNull(name);
final T[] constants = type.getEnumConstants();
if (constants == null) {
throw conversionException(type, name);
}
for (final T constant : constants) {
if (((Enum<?>) constant).name().equals(name)) {
return constant;
}
}
throw conversionException(type, name);
}
/**
* {@inheritDoc}
*/
@Override
protected String convertToString(
final Object value)
throws Throwable {
if (value instanceof Enum) {
return ((Enum<?>) value).name();
} else if (value instanceof String) {
return value.toString();
} else {
throw conversionException(String.class, value);
}
}
/**
* Registers {@code EnumConverter.GENERIC} for the {@code Enum} class in
* the singleton Apache commons bean utils converter.
* <p>
* Note that the default {@code ConvertUtilsBean} implementation doesn't
* fallback to {@code Enum} when converting enumerations. Instances of
* {@code EnumConvertUtilsBean} or {@code EnumConvertUtilsBean2} must
* be used to this converter apply.
*/
public static void register() {
BeanUtilsBean.getInstance().getConvertUtils().register(
EnumConverter.GENERIC,
Enum.class);
}
/**
* Registers {@code EnumConverter.GENERIC} for the {@code Enum} class in
* the specified Apache commons bean utils converter.
* <p>
* Note that the default {@code ConvertUtilsBean} implementation doesn't
* fallback to {@code Enum} when converting enumerations. Instances of
* {@code EnumConvertUtilsBean} or {@code EnumConvertUtilsBean2} must
* be used to this converter apply.
*
* @param converter The Apache commons bean utils converter to register to
*/
public static void register(
final ConvertUtilsBean converter) {
Validate.notNull(converter).register(
EnumConverter.GENERIC,
Enum.class);
}
/**
* Registers {@code EnumConverter.GENERIC_DEFAULT} for the {@code Enum}
* class in the singleton Apache commons bean utils converter.
* <p>
* Note that the default {@code ConvertUtilsBean} implementation doesn't
* fallback to {@code Enum} when converting enumerations. Instances of
* {@code EnumConvertUtilsBean} or {@code EnumConvertUtilsBean2} must
* be used to this converter apply.
*/
public static void registerWithDefault() {
BeanUtilsBean.getInstance().getConvertUtils().register(
EnumConverter.GENERIC_DEFAULT,
Enum.class);
}
/**
* Registers {@code EnumConverter.GENERIC_DEFAULT} for the {@code Enum}
* class in the specified Apache commons bean utils converter.
* <p>
* Note that the default {@code ConvertUtilsBean} implementation doesn't
* fallback to {@code Enum} when converting enumerations. Instances of
* {@code EnumConvertUtilsBean} or {@code EnumConvertUtilsBean2} must
* be used to this converter apply.
*
* @param converter The Apache commons bean utils converter to register to
*/
public static void registerWithDefault(
final ConvertUtilsBean converter) {
Validate.notNull(converter).register(
EnumConverter.GENERIC_DEFAULT,
Enum.class);
}
}