[groovy-user] 1.6-RC-1 and ResourceBundle (classloading issue ?)

5 views
Skip to first unread message

melix

unread,
Dec 23, 2008, 10:24:45 AM12/23/08
to us...@groovy.codehaus.org

Hi,

I've got two .properties files in the classpath :

i18n/xtirp.properties
i18n/xtirp_fr.properties

Now I'm having a serious issue with the latest Groovy release. Has anything
changed in the groovy class loader ? Because the following line doesn't work
anymore :

I'm getting the following stack trace :

Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at com.lingway.xtirp.Launcher.class$(Launcher.groovy)
at
com.lingway.xtirp.Launcher.$get$$class$com$lingway$xtirp$RuleManager(Launcher.groovy)
at com.lingway.xtirp.Launcher.main(Launcher.groovy:51)
Caused by: java.util.MissingResourceException: Can't find bundle for base
name i18n.xtirp, locale fr_FR
at
java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1521)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1260)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:715)
at java_util_ResourceBundle$getBundle.call(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:43)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at com.lingway.xtirp.RuleManager.<clinit>(RuleManager.groovy:19)
... 5 more

Reverting back to 1.5.7 there's no problem. I didn't notice any error with
beta 1, but reproduced it with beta 2. So I guess there's been some change
between those versions. Any idea ?
--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21146272.html
Sent from the groovy - user mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


melix

unread,
Dec 23, 2008, 10:25:58 AM12/23/08
to us...@groovy.codehaus.org

oops, here's the line that throws the exception :

private final static ResourceBundle resourceBundle =
ResourceBundle.getBundle("i18n.xtirp");

--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21146299.html

Guillaume Laforge

unread,
Dec 30, 2008, 4:32:35 PM12/30/08
to us...@groovy.codehaus.org
Hi Cédric,

I haven't looked at your problem (ah Christmas times...), but I was
curious if you had made any progress on your problem?

--
Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one

melix

unread,
Jan 4, 2009, 8:00:39 AM1/4/09
to us...@groovy.codehaus.org

Sorry, vacation time ;) BTW, happy new year.

I couldn't take another look at the problem, but I guess it's still here. It
would be a pity for me if Groovy 1.6 was released with such a bug (if it is
a bug, I'm not sure, but still there's a change in the behaviour) because
I'd have to keep with 1.5.7.

--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21275962.html

melix

unread,
Jan 11, 2009, 5:05:40 AM1/11/09
to us...@groovy.codehaus.org

I'm quite disturbed with this bug : I've made further investigations, and
it's blowing up my mind. If I build my application jar with Maven, then run
the application thanks to this jar, I've got no problem. If I run my
application from IntelliJ, then the problem occurs. It does not seems to be
a problem with my IDE configuration since my .properties files are properly
copied to the classes directory.

Hence, the problem disappears when moving back to 1.6 beta 1 and appears
with beta 2, so there must have been some change between those releases that
triggers the bug. Is there any chance someone sees where the problem lies ?

--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21397578.html

Jochen Theodorou

unread,
Jan 11, 2009, 11:22:21 AM1/11/09
to us...@groovy.codehaus.org
melix schrieb:

> I'm quite disturbed with this bug : I've made further investigations, and
> it's blowing up my mind. If I build my application jar with Maven, then run
> the application thanks to this jar, I've got no problem. If I run my
> application from IntelliJ, then the problem occurs. It does not seems to be
> a problem with my IDE configuration since my .properties files are properly
> copied to the classes directory.
>
> Hence, the problem disappears when moving back to 1.6 beta 1 and appears
> with beta 2, so there must have been some change between those releases that
> triggers the bug. Is there any chance someone sees where the problem lies ?

so the difference between the IDE version and he maven version is not
only the IDe and maven, but also the groovy version? Did you compare the
jars? I mean the manifest and if the jar contains the property file.
Also it would be good to compare only the groovy versions, not
additionally change the environment.

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/

melix

unread,
Jan 11, 2009, 11:48:28 AM1/11/09
to us...@groovy.codehaus.org

To be clearer : my program is developped with IntelliJ as a Maven project,
with a Groovy facet (autodetected). So, when I'm using Groovy 1.5.7 or
1.6.0-beta1, I've got no problem : the project compiles within the IDE, and
there's no exception. The jar, produced with the package target includes all
the resources.

Starting from Groovy 1.6.0-beta2, I'm not able to run my program from the
IDE anymore : the exception occurs (with both Groovy 1.6.0-beta2 and rc1).
However, if I build my program with maven package, then the produced jar
runs perfectly. The difference with the IDE is that in that case, the
resources are bundled in the jar, while when running the program from the
IDE, the resources are just copied by the IDE in the classes output
directory. I don't understand why the classloader resolves my resources when
packaged in a jar, and not in the classes directory, starting from 1.6.0
beta 2.

--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21401228.html


Sent from the groovy - user mailing list archive at Nabble.com.

Jochen Theodorou

unread,
Jan 11, 2009, 12:23:25 PM1/11/09
to us...@groovy.codehaus.org
melix schrieb:

> To be clearer : my program is developped with IntelliJ as a Maven project,
> with a Groovy facet (autodetected). So, when I'm using Groovy 1.5.7 or
> 1.6.0-beta1, I've got no problem : the project compiles within the IDE, and
> there's no exception. The jar, produced with the package target includes all
> the resources.
>
> Starting from Groovy 1.6.0-beta2, I'm not able to run my program from the
> IDE anymore : the exception occurs (with both Groovy 1.6.0-beta2 and rc1).
> However, if I build my program with maven package, then the produced jar
> runs perfectly. The difference with the IDE is that in that case, the
> resources are bundled in the jar, while when running the program from the
> IDE, the resources are just copied by the IDE in the classes output
> directory. I don't understand why the classloader resolves my resources when
> packaged in a jar, and not in the classes directory, starting from 1.6.0
> beta 2.

it finds the resources in the jar, because the jar and all its files are
part of the classpath. The first things would maybe to use getResource
to test if the file is found before we proceed to bundles. If
getResource does not work, then using a File should confirm the file is
actually where you expect it to be. also the question is what
classloader is used....

to ensure the right classloader is used, you should try getResource with
this.class.classLoader. and if that works, but getBundle not, you should
try ResourceBundle.getBundle("i18n.xtirp", Locale.getDefault(),
this.class.classLoader)

I currently wonder if the call site classes classloaders themself where
used in beta1 like they are used now already.... maybe these have an
error and do not allow the correct propagation of the request... on the
other hand the ResourceBundle.getBundle("i18n.xtirp",
Locale.getDefault(), this.class.classLoader) should work even if that is
the case. So if that does not work, then the error is somewhere else.

melix

unread,
Jan 11, 2009, 3:14:10 PM1/11/09
to us...@groovy.codehaus.org

Here's the result. With the following test code :
class ClassLoadingDebug {

public static void main(String ... args) {

try {
println ResourceBundle.getBundle("i18n.xtirp")
} catch (e) {
e.printStackTrace()
}
try {
println ClassLoadingDebug.class.getResource("/i18n/xtirp.properties")
} catch (e) {
e.printStackTrace()
}
try {
println ResourceBundle.getBundle("i18n.xtirp", Locale.getDefault(),
ClassLoadingDebug.class.classLoader)
} catch (e) {
e.printStackTrace()
}
}

Only the first call produces an error. The calls
ClassLoadingDebug.class.getResource("/i18n/xtirp.properties") and
ResourceBundle.getBundle("i18n.xtirp", Locale.getDefault(),
ClassLoadingDebug.class.classLoader) both return an instance.

--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21403612.html


Sent from the groovy - user mailing list archive at Nabble.com.

Jochen Theodorou

unread,
Jan 11, 2009, 9:29:24 PM1/11/09
to us...@groovy.codehaus.org
melix schrieb:

> Here's the result. With the following test code :
> class ClassLoadingDebug {
>
> public static void main(String ... args) {
>
> try {
> println ResourceBundle.getBundle("i18n.xtirp")
> } catch (e) {
> e.printStackTrace()
> }
> try {
> println ClassLoadingDebug.class.getResource("/i18n/xtirp.properties")
> } catch (e) {
> e.printStackTrace()
> }
> try {
> println ResourceBundle.getBundle("i18n.xtirp", Locale.getDefault(),
> ClassLoadingDebug.class.classLoader)
> } catch (e) {
> e.printStackTrace()
> }
> }
>
> Only the first call produces an error. The calls
> ClassLoadingDebug.class.getResource("/i18n/xtirp.properties") and
> ResourceBundle.getBundle("i18n.xtirp", Locale.getDefault(),
> ClassLoadingDebug.class.classLoader) both return an instance.

I see... so there is a possibility that the call site class loader is
doing something wrong.

melix

unread,
Jan 12, 2009, 7:35:01 AM1/12/09
to us...@groovy.codehaus.org

Should I raise an issue ?

--
View this message in context: http://www.nabble.com/1.6-RC-1-and-ResourceBundle-%28classloading-issue--%29-tp21146272p21413567.html


Sent from the groovy - user mailing list archive at Nabble.com.

Guillaume Laforge

unread,
Jan 12, 2009, 7:44:24 AM1/12/09
to us...@groovy.codehaus.org
Please do so, yes.

--

Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one

---------------------------------------------------------------------

Jochen Theodorou

unread,
Jan 13, 2009, 7:37:39 AM1/13/09
to us...@groovy.codehaus.org
melix schrieb:

> Should I raise an issue ?

thanks for rising the issue

I looked a bit into it and I found the code that gets the class loader.
Basically it tries to crawl the stack up by 2 element and then gets the
class loader for the class there. In Java, where one method call will
cause one element to be added there this is fine. In Groovy a method
call usually involves more then one element being added to the stack. As
a result that method will not select the stack frame, that made the
call, but probably some reflection code. And that again usually means
that the APPLoader will be asked. That means if you gave the resource
onto the class path, then it should do. Since a certain classloader is
required then I disencourage the usage without explicit classloader.

To confirm this I have one more thing to test for you. Could you try

println ClassLoader.getSystemClassLoader()


println ResourceBundle.getBundle("i18n.xtirp", Locale.getDefault(),

ClassLoader.getSystemClassLoader())

for beta1 and rc1? ClassLoader.getSystemClassLoader() should be the
APPLoader. The code should behave the same for beta1 and rc1. If the
bundle is not found this way, then well.. not sure yet...

of course there is one point that actually may make a difference... in
rc1 he first call of a method at a certain position does not use the
shortcut, instead it uses reflection. 1.5.x does always use reflection.
in rc1 if the same place is called a second time, then (if no type
changes did occur) we use a generated class and do the call using that
class. The stack height for this kind of call is only two elements big,
so that if the generated class does have the correct loader wiring it
would allow the correct usage of this method. Maybe in beta1 we did sue
that right away? Not sure... but this gives a new thing you could try:

2.times {


try {
println ResourceBundle.getBundle("i18n.xtirp")
} catch (e) {}
}

in rc1 it is to be expected that the first call will fail, but the
second call might work. If it works we have to think about what to do.

Danno Ferrin

unread,
Jan 16, 2009, 8:28:53 AM1/16/09
to us...@groovy.codehaus.org
Reproduced and fixed on 1.6 and 1.7.  Figuring out that it was the stack trace height helped me in fising it, thanks Jochen,  What I did was I created a static DGM method to override te .getResource(String,[Locale]) methods and do our own stack sniffing to get the calling classpath.  So now it is sensitive to the prefix names of the classes instead of the height.  So this limits the problem to sun.reflect, groovy.lang, org.codehaus.groovy.runtime, and org.codehaus.groovy.reflect, a set of packages that we can safely tell the users "don't do that" if it happens because of that.

--Danno
--
------------------------------------------------------
I'm Danno Ferrin, and I approved this message.

Jochen Theodorou

unread,
Jan 16, 2009, 8:36:13 AM1/16/09
to us...@groovy.codehaus.org
Danno Ferrin schrieb:

> Reproduced and fixed on 1.6 and 1.7. Figuring out that it was the stack
> trace height helped me in fising it, thanks Jochen, What I did was I
> created a static DGM method to override te .getResource(String,[Locale])
> methods and do our own stack sniffing to get the calling classpath.

you used ReflectionUtils.getCallingClass(), that's good.

> So
> now it is sensitive to the prefix names of the classes instead of the
> height. So this limits the problem to sun.reflect, groovy.lang,
> org.codehaus.groovy.runtime, and org.codehaus.groovy.reflect, a set of
> packages that we can safely tell the users "don't do that" if it happens
> because of that.

yes, that should do it.... of course that is not the most performant
solution, but well...

Danno Ferrin

unread,
Jan 16, 2009, 9:22:55 AM1/16/09
to us...@groovy.codehaus.org
On Fri, Jan 16, 2009 at 6:36 AM, Jochen Theodorou <blac...@gmx.org> wrote:
Danno Ferrin schrieb:

Reproduced and fixed on 1.6 and 1.7.  Figuring out that it was the stack trace height helped me in fising it, thanks Jochen,  What I did was I created a static DGM method to override te .getResource(String,[Locale]) methods and do our own stack sniffing to get the calling classpath.

you used ReflectionUtils.getCallingClass(), that's good.


So now it is sensitive to the prefix names of the classes instead of the height.  So this limits the problem to sun.reflect, groovy.lang, org.codehaus.groovy.runtime, and org.codehaus.groovy.reflect, a set of packages that we can safely tell the users "don't do that" if it happens because of that.

yes, that should do it.... of course that is not the most performant solution, but well...


It's about the same as Sun's versions, they use the same reflection calls underneath the covers that our ReflectionUtils does with less string checking.  But the performant solution in both cases is to either cache the RB outside of the critical section of code, or specify the locale and classloader manually.  But fetching a RB in a tight loop, not really a good idea anyway.

Guillaume Laforge

unread,
Jan 16, 2009, 10:06:22 AM1/16/09
to us...@groovy.codehaus.org
Updating to 1.7, I've now got 2 test failures with the recent changes
on Mac OS X / Java 5.

UberTestCaseGroovySourceSubPackages testWithLocale Error Expression:
(rb.getString(yes) == yes)

java.lang.AssertionError: Expression: (rb.getString(yes) == yes)
at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:373)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:658)
at groovy.util.ResourceBundleTest$_testWithLocale_closure2.doCall(ResourceBundleTest.groovy:24)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:892)
at groovy.lang.Closure.call(Closure.java:280)
at groovy.lang.Closure.call(Closure.java:293)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.times(DefaultGroovyMethods.java:7062)
at org.codehaus.groovy.runtime.dgm$522.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)


at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:43)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)

at groovy.util.ResourceBundleTest.testWithLocale(ResourceBundleTest.groovy:21)


UberTestCaseGroovySourceSubPackages testWithClassLoader Error Expression:
(rb.getString(yes) == yes)

java.lang.AssertionError: Expression: (rb.getString(yes) == yes)
at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:373)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:658)
at groovy.util.ResourceBundleTest$_testWithClassLoader_closure3.doCall(ResourceBundleTest.groovy:39)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:892)
at groovy.lang.Closure.call(Closure.java:280)
at groovy.lang.Closure.call(Closure.java:293)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.times(DefaultGroovyMethods.java:7062)
at org.codehaus.groovy.runtime.dgm$522.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)


at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:43)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)

at groovy.util.ResourceBundleTest.testWithClassLoader(ResourceBundleTest.groovy:36)

--

Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one

---------------------------------------------------------------------

Danno Ferrin

unread,
Jan 16, 2009, 10:18:55 AM1/16/09
to us...@groovy.codehaus.org
So... is French your default language?  Let me check in some tweaks, I think it's a resource bundle thing, I miscalculated the way it drops down to the default bundle.

--Danno
--

Guillaume Laforge

unread,
Jan 16, 2009, 10:22:58 AM1/16/09
to us...@groovy.codehaus.org
Yup, looks like so:

assert "fr_FR" == Locale.default.toString()

Danno Ferrin

unread,
Jan 16, 2009, 10:34:35 AM1/16/09
to us...@groovy.codehaus.org
Ok, give head another shot.  If it fails can you also attach the system.out output? I've dropped in some debugging code.


On Fri, Jan 16, 2009 at 8:22 AM, Guillaume Laforge <glaf...@codehaus.org> wrote:
Yup, looks like so:

assert "fr_FR" == Locale.default.toString()


On Fri, Jan 16, 2009 at 4:18 PM, Danno Ferrin <danno....@shemnon.com> wrote:
> So... is French your default language?  Let me check in some tweaks, I think
> it's a resource bundle thing, I miscalculated the way it drops down to the
> default bundle.
>
> --Danno
>
> On Fri, Jan 16, 2009 at 8:06 AM, Guillaume Laforge <glaf...@codehaus.org>
> wrote:
>>
>> Updating to 1.7, I've now got 2 test failures with the recent changes
>> on Mac OS X / Java 5.
>>
>> UberTestCaseGroovySourceSubPackages     testWithLocale  Error
>> Expression:
>> (rb.getString(yes) == yes)

Guillaume Laforge

unread,
Jan 16, 2009, 10:40:46 AM1/16/09
to us...@groovy.codehaus.org
Build fixed for me, thank you very much Danno!

--

Reply all
Reply to author
Forward
0 new messages