commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Oliver Heger (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (BEANUTILS-450) BeanUtilsBean.getInstance() pseudo-singleton causes problems with Java 7 parallelized class loader
Date Wed, 06 Nov 2013 21:05:18 GMT

    [ https://issues.apache.org/jira/browse/BEANUTILS-450?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13815289#comment-13815289
] 

Oliver Heger commented on BEANUTILS-450:
----------------------------------------

The fact that enabling the Java console "fixes" the problem is pretty suspicious. Probably,
the console slows down execution so that a race condition is just avoided. It would be better
to adapt the design to make timing more explicit.

Going back to the original solution with the converter registration in a static block, it
would be possible to add an utility method to the {{UtilitiesClass}} class which just handles
the conversion by delegating to {{ConvertUtils}}:

{code}
public static Object convert(Object value, Class<?> targetCls) {
    return ConvertUtils.convert(value, targetCls);
}
{code}

Now rather than accessing {{ConvertUtils}} directly, client code calls the new static method
of the utilities class. Because the converters are registered in a static block in the same
class, it should be guaranteed that registration is complete when the converters are actually
used. I am curious whether the bug still occurs in this constellation.

> 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
>         Environment: Java 7u25+, Windows 7 32-bit desktop environments
>            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:
> {code}
> public class UtilitiesClass {
>    ...
>    static {
>        registerConverters();
>    }
>    public static void registerConverters() {
>        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);
>    }
>    ...
> }
> {code}
> 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)

Mime
View raw message