Matthew Hall created BEANUTILS-450:
--------------------------------------
Summary: BeanUtilsBean.getInstance() pseudo-singleton causes
problems with Java 7 parallelized class loader
Key: BEANUTILS-450
URL: https://issues.apache.org/jira/browse/BEANUTILS-450
Project: Commons BeanUtils
Issue Type: Bug
Components: Bean / Property Utils, ConvertUtils & Converters
Affects Versions: 1.7.0
Reporter: Matthew Hall
Priority: Blocker
>From an email I sent to the BeanUtils users mailing list:
We recently tracked a bug in our software that started showing up with Java 7
back to an incompatibility between BeanUtilsBean.getInstance() pseudo-singleton
instance model, Java 7’s parallelized class loader, and the fact that we were
registering Converters with ConvertUtils inside of a static class-level block.
As far as I’m able to tell, this wasn’t a problem in previous versions of Java
because the class loader was not parallelized, meaning that the class loader
that handled the registration of our converters was the same class loader that
was in use when ConvertUtilsBean.getInstance() was invoked. Now, with Java 7,
it seems that there is no guarantee that the class loader that executes the
static block containing the Converter registration is the same one in use when
ConvertUtilsBean.getInstance() is invoked, meaning that our custom Converters
are not necessarily available everywhere they used to be.
I’m writing to the list today to ask three things about this situation:
1. First off, is this the correct explanation for the reason that it seems
we’re not guaranteed to have our custom Converters loaded in Java 7.
2. In order to ensure that a different class loader thread is not in use when
the Converters are registered with ConvertUtils, we’ve moved this registration
from a static class-level block into a user interface setup method that is
executed before the Converters are used.
3. Given that Java 7 introduced parallelized class loading in the base
ClassLoader and that BeanUtilsBean builds instances on a per-classloader basis,
should this issue be raised to the BeanUtils developers?
Below you’ll find some pseudocode that illustrates our situation:
public class UtilitiesClass {
...
static {
ConvertUtils.register(new OurCustomColorConverter(),
java.awt.Color.class);
}
...
}
public class MainGUIClass {
...
public static void main(String[] args) {
MainGUIClass mainGui = new MainGUIClass();
mainGui.setup();
mainGui.show();
}
public void setup() {
UIManager.setLookAndFeel(new LookAndFeelClass());
}
public void show() {
((OurLookAndFeelClass) UIManager.getLookAndFeel()).getColor();
}
...
}
public class LookAndFeelClass extends LookAndFeel {
...
public java.awt.Color getColor(String colorString) {
return (java.awt.Color) ConvertUtils.convert("someValidColorString",
java.awt.Color.class);
}
...
}
In the above example, the cast of the results of ConvertUtils.convert to Color
in LookAndFeelClass.getColor(String) sometimes results in a runtime exception
with the message “java.lang.String cannot be cast to java.awt.Color.”. This
appears to be due to the fact that ConvertUtils.convert() fails over to the
built-in String.class Converter if it cannot find a Converter for the specified
class. In production environments, it was completely unpredictable as to when
this would happen and what would make the problem go away.
The fix we implemented was to move the registration of
OurCustomColorConverter() from the static block inside of UtilitiesClass to the
first line of MainGUIClass.setup(), before the LookAndFeel is loaded. Will this
fix be sufficient, or does it still suffer from the thread issue, if that is
indeed the root cause of the problem?
--
This message was sent by Atlassian JIRA
(v6.1#6144)