Каков наилучший способ зарегистрировать конвертер для всех подклассов определенного класса при использовании Commons BeanUtils? - PullRequest
4 голосов
/ 10 февраля 2011

Например, если я хочу зарегистрировать конвертер для всех экземпляров java.util.Map, есть ли способ сделать это:

new BeanUtilsBean().getConvertUtils().register(new MyConverter(), Map.class);

, где будет вызван метод MyConverter#convert()любой экземпляр карты (например, HashMap)?

Предпосылкой для этого является то, что я использую BeanUtils для наполнения различных различных bean-компонентов из базы данных.Некоторые из их свойств являются перечислениями, которые реализуют определенный интерфейс, и для установки их значений необходима специальная подпрограмма.Я надеялся зарегистрировать один класс конвертера для всех реализаций рассматриваемого интерфейса, но не смог найти способ сделать это, поэтому мне пришлось делать это на лету, проверяя класс каждого свойства в bean-компонентах изарегистрировать мой класс конвертера, если они оказались экземплярами этого интерфейса:

BeanUtilsBean b = new BeanUtilsBean();
Class< ? > propertyType = pu.getPropertyType(this, setterName);

if (isImplementationOfMyInterface(propertyType)) {
    b.getConvertUtils().register(new MyConverter(), propertyType);
}

b.setProperty(this, setterName, value);

Это кажется довольно неприятным, и я уверен, что должен быть лучший способ сделать это?

Ответы [ 2 ]

6 голосов
/ 23 декабря 2012

Вы можете переопределить ConvertUtilsBean. В следующем коде добавлена ​​поддержка Enum, но вы можете сделать то же самое для Map:

BeanUtilsBean.setInstance(new BeanUtilsBean(new EnumAwareConvertUtilsBean()));

Определения классов:

public class EnumAwareConvertUtilsBean extends ConvertUtilsBean2 {

    private static final EnumConverter ENUM_CONVERTER = new EnumConverter();

    @Override
    public Converter lookup(Class pClazz) {
        final Converter converter = super.lookup(pClazz);

        if (converter == null && pClazz.isEnum()) {
            return ENUM_CONVERTER;
        } else {
            return converter;
        }
    }

}

public class EnumConverter extends AbstractConverter {

    private static final Logger LOGGER = LoggerFactory.getLogger(EnumConverter.class);

    @Override
    protected String convertToString(final Object pValue) throws Throwable {
        return ((Enum) pValue).name();
    }

    @Override
    protected Object convertToType(final Class pType, final Object pValue)
        throws Throwable
    {
        // NOTE: Convert to String is handled elsewhere

        final Class<? extends Enum> type = pType;
        try {
            return Enum.valueOf(type, pValue.toString());
        } catch (final IllegalArgumentException e) {
            LOGGER.warn("No enum value \""
                + pValue
                + "\" for "
                + type.getName());
        }

        return null;
    }

    @Override
    protected Class getDefaultType() {
        return null;
    }

}

Я получил решение, прочитав сообщение в блоге и комментарии от http://www.bitsandpix.com/entry/java-beanutils-enum-support-generic-enum-converter/

2 голосов
/ 06 октября 2011

Пытался сделать то же самое (мой вариант использования был общим конвертером для всех типов Enum), но из того, что я мог видеть в коде, ConvertUtils поддерживает только прямое отображение между конвертером и классом, и нет способа зарегистрировать базовый класс или интерфейс.

По сути, он использует Map, где ключом является класс и значение конвертера, а чтобы получить правильный конвертер на основе класса, он просто выполняет Map # get.

...