Search code examples
javathread-safetythread-localapache-commons-beanutils

Are register of Converters in BeanUtils thread-local?


I have a web project where BeanUtils is used to manipulation beans.

In my code, in order to make BeanUtils transfer string records into java.util.Date fields properly, a DateConverter is registered into ConvertUtils class like that:

ConvertUtils.register(dateConverter, Date.class);

Moreover, In my project, different date formats is needed in different Actions, So, I registered different converters in different actions like that:

public void Action1(){
    DateTimeConverter dtConverter = new DateConverter();
    dtConverter.setPatterns(dateFormats1);
    ConvertUtils.register(dtConverter, Date.class);
    ...
    BeanUtils.populate(myBean1, hashMap1);
}
public void Action2(){
    DateTimeConverter dtConverter = new DateConverter();
    dtConverter.setPatterns(dateFormats2);
    ConvertUtils.register(dtConverter, Date.class);
    ...
    BeanUtils.populate(myBean2, hashMap2);
}

But later, I noticed that registered Converter with same target class (Date here) will replace each other. So if ConvertUtils.register operation is not thread local, problems caused by concurrence may happen here, even through my website haven`t met any yet.

So, would converter registered in one thread replace converter registered in another thread? If so, is there any work around for my circumstance?


Solution

  • Apache commons beanutils uses a ContextClassLoaderLocal to manage the framework's instances. The concept is similar to a ThreadLocal except that it binds an instance to a thread's context class loader.

    So when the threads that execute Action1 and Action2 share the same context class loader a change to the ConverterUtils in one action will affect the other.

    To be safe you can use an own instance of a BeanUtilsBean in each action, e.g.

    public void Action1(){
        BeanUtilsBean beanUtils = new BeanUtilsBean();
        ConvertUtilsBean convertUtils = beanUtils.getConvertUtils();
        DateTimeConverter dtConverter = new DateConverter();
        dtConverter.setPatterns(dateFormats1);
        convertUtils.register(dtConverter, Date.class);
        ...
        beanUtils.populate(myBean1, hashMap1);
    }
    

    Of course it would be better to configure the BeanUtilsBean once in the constructor of your class and just use it.