What's the best way to register a Converter for all subclasses of a particular class when using Commons BeanUtils?

淺唱寂寞╮ 提交于 2019-12-07 11:15:43

问题


For example, if I wished to register a Converter for all instances of java.util.Map, is there some way of doing this:

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

where the MyConverter#convert() method would be called for any instance of a Map (for instance a HashMap)?

The background to this is that I'm using BeanUtils to populate various different beans from a database. Some of their properties are enums that implement a particular interface, and to set their values a custom routine is needed. I'd hoped to register a single converter class for all implementations of the interface in question but couldn't find a way of doing this, so ended up having to do it on the fly by inspecting the class of every property in the beans and registering my converter class if they happened to be instances of this interface:

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

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

b.setProperty(this, setterName, value);

This seems rather nasty, and I'm sure there must be a better way of doing this?


回答1:


You can override ConvertUtilsBean. The following code adds support for Enum, but you can do the same for Map:

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

Class definitions:

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;
    }

}

I got the solution from reading the blog post and comments from http://www.bitsandpix.com/entry/java-beanutils-enum-support-generic-enum-converter/




回答2:


Was trying to to the same thing (my use case was a common converter for all type of Enum) but from what I could see in the code ConvertUtils only support direct mapping between converter and class and there is no way to register a base class or an interface.

Basically it's using a Map where the key is the class and the value the converter and to get the proper converter based in the class it simply does a Map#get.



来源:https://stackoverflow.com/questions/4956714/whats-the-best-way-to-register-a-converter-for-all-subclasses-of-a-particular-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!