You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Grzegorz Kossakowski <gr...@tuffmail.com> on 2008/08/15 16:02:25 UTC

RCL plug-in and different classloaders issues

Hi,

I'm just playing around with Cocoon's RCL plug-in in some more complicated scenario and stumbled 
upon a problem when the same class is loaded by two different classloaders.

In brief, following steps are performed:
1. Class from my block is loaded using ResourceStoreClassLoader. Let's call this class MAIN.
2. This class accesses some static method of another class loaded by ResourceStoreClassLoader 
(because this class comes from my block as well) and sets some value on static field. Let's call 
this class STATIC
3. Then another class (3RDPARTY) is being loaded which is not part of my block, it's from 
third-party jar. It's loaded by parent classloader to ResourceStoreClassLoader. As part of 
configuration of this class I pass a name of class which is some kind of extension point and is 
implemented by class coming from my block; let's call this class EXTENSION.
4. 3RDPARTY creates new instance of EXTENSION class (and this class is again not loaded by 
ResourceStoreClassLoader but by parent), but in EXTENSION class one tries to access field set in STATIC.
5. While EXTENSION tries to access STATIC, STATIC is being loaded again, using parent classloader. 
The value in STATIC is gone, obviously.

So the basic problem is that, this STATIC class is loaded by two different classloaders.

I'm wondering if there is any kind of general solution to such problems. The only one I can think of 
is to enforce loading of 3RDPARTY class by ResourceStoreClassLoader so everything stays within one 
classloader and even reflection tricks are not dangerous. However, that would mean that one needs to 
modify commons-jci project.

Is there any simpler method?

-- 
Grzegorz Kossakowski

Re: RCL plug-in and different classloaders issues

Posted by Vadim Gritsenko <va...@reverycodes.com>.
On Aug 15, 2008, at 10:02 AM, Grzegorz Kossakowski wrote:

> I'm just playing around with Cocoon's RCL plug-in in some more  
> complicated scenario and stumbled upon a problem when the same class  
> is loaded by two different classloaders.
>
> In brief, following steps are performed:
> 1. Class from my block is loaded using ResourceStoreClassLoader.  
> Let's call this class MAIN.
> 2. This class accesses some static method of another class loaded by  
> ResourceStoreClassLoader (because this class comes from my block as  
> well) and sets some value on static field. Let's call this class  
> STATIC
> 3. Then another class (3RDPARTY) is being loaded which is not part  
> of my block, it's from third-party jar. It's loaded by parent  
> classloader to ResourceStoreClassLoader. As part of configuration of  
> this class I pass a name of class which is some kind of extension  
> point and is implemented by class coming from my block; let's call  
> this class EXTENSION.
> 4. 3RDPARTY creates new instance of EXTENSION class (and this class  
> is again not loaded by ResourceStoreClassLoader but by parent), but  
> in EXTENSION class one tries to access field set in STATIC.

What I don't get is why you have STATIC class in two places. You  
should have it only in one place. E.g., EXTENSION as well as STATIC  
and all other required classes should be in single jar file which  
should be placed side by side with the 3RDPARTY jar file.

RCL will not have STATIC file and will have to use the one loaded by  
parent. Right?

Vadim


> 5. While EXTENSION tries to access STATIC, STATIC is being loaded  
> again, using parent classloader. The value in STATIC is gone,  
> obviously.
>
> So the basic problem is that, this STATIC class is loaded by two  
> different classloaders.
>
> I'm wondering if there is any kind of general solution to such  
> problems. The only one I can think of is to enforce loading of  
> 3RDPARTY class by ResourceStoreClassLoader so everything stays  
> within one classloader and even reflection tricks are not dangerous.  
> However, that would mean that one needs to modify commons-jci project.
>
> Is there any simpler method?
>
> -- 
> Grzegorz Kossakowski


Re: RCL plug-in and different classloaders issues

Posted by Torsten Curdt <tc...@apache.org>.
On Aug 17, 2008, at 14:14, Grzegorz Kossakowski wrote:

> Torsten Curdt pisze:
>> Well, the only thing I could think of right now:
>> Define a common interface that is loaded by parent. Delegate to an  
>> implementation of that from EXTENSION. That should work.
>> But if you want to extend something that is changing (and not has a  
>> fix interface) you will have to load it from the RSCL.
>
> Yes, that could work but there is another problem. Once EXTENSION  
> obtains ApplicationContext and tries to load some beans  
> ClassCastExceptions will be thrown because EXTENSION holds  
> references to interface classes loaded by parent and  
> ApplicationContext holds references to interfaces loaded by RCL. In  
> short: a mess.

Not entirely sure that really is the case like that ...but anyway.

>> Well, the RCL currently is pointed to a folder of class files. It  
>> should not be too hard to also have it monitor a directory of jars.
>
> I know that's its not hard when it comes to modifying the code but I  
> was wondering if it's a good idea in general to load everything  
> using ReloadingClassLoader. It was not done in the first time so I  
> thought that someone had a good reason to do that.

Well, the question is what does change - transitively. In this case  
you extending something that is (potentially) changing.

> Anyway, I decided to rewrite 3RDPARTY the way that I can inject my  
> own extensions so I could get rid of static class completely. God  
> bless open source 3RDPARY dependencies ;-)

Hehehe :)

> If anyone else is reading this thread: Lesson for everyone - static  
> classes and variables are not so static when you use different  
> classloaders. Moreover, they are not a good idea in any case.

+1 :)

cheers
--
Torsten


Re: RCL plug-in and different classloaders issues

Posted by Reinhard Pötz <re...@apache.org>.
Grzegorz Kossakowski wrote:
> I know that's its not hard when it comes to modifying the code but I was
> wondering if it's a good idea in general to load everything using
> ReloadingClassLoader. It was not done in the first time so I thought
> that someone had a good reason to do that.

When I wrote the code, I hadn't a use case for it.

-- 
Reinhard Pötz                           Managing Director, {Indoqa} GmbH
                         http://www.indoqa.com/en/people/reinhard.poetz/

Member of the Apache Software Foundation
Apache Cocoon Committer, PMC member                  reinhard@apache.org
________________________________________________________________________

Re: RCL plug-in and different classloaders issues

Posted by Grzegorz Kossakowski <gr...@tuffmail.com>.
Torsten Curdt pisze:
> 
> Well, the only thing I could think of right now:
> 
> Define a common interface that is loaded by parent. Delegate to an 
> implementation of that from EXTENSION. That should work.
> But if you want to extend something that is changing (and not has a fix 
> interface) you will have to load it from the RSCL.

Yes, that could work but there is another problem. Once EXTENSION obtains ApplicationContext and 
tries to load some beans ClassCastExceptions will be thrown because EXTENSION holds references to 
interface classes loaded by parent and ApplicationContext holds references to interfaces loaded by 
RCL. In short: a mess.

> Well, the RCL currently is pointed to a folder of class files. It should 
> not be too hard to also have it monitor a directory of jars.

I know that's its not hard when it comes to modifying the code but I was wondering if it's a good 
idea in general to load everything using ReloadingClassLoader. It was not done in the first time so 
I thought that someone had a good reason to do that.

Anyway, I decided to rewrite 3RDPARTY the way that I can inject my own extensions so I could get rid 
of static class completely. God bless open source 3RDPARY dependencies ;-)

If anyone else is reading this thread: Lesson for everyone - static classes and variables are not so 
static when you use different classloaders. Moreover, they are not a good idea in any case.

Thanks for help.

-- 
Best regards,
Grzegorz Kossakowski

Re: RCL plug-in and different classloaders issues

Posted by Torsten Curdt <tc...@apache.org>.
>> Well, if you think about it: with this setup there is no other way  
>> around to have the parent classloader know of the static class to  
>> have this problem resolved. As you can't (?) modify the parent  
>> classloader your only chance is to have the EXTENSION loaded by the  
>> RSCL as well.
>
> But how this can be enforced? I mean, 3RDPARTY is loaded by parent  
> and 3RDPARTY, when tries to create a new instance of EXTENSION uses  
> it's own classloader thus uses parent. The only solution I can see  
> here is that I load 3RDPARTY using classloader coming from JCI so  
> then EXTENSION will be loaded with this classloader as well.
>
> Am I missing something?

No, I was trying to say the same thing :)

>> I would take a step back and re-think the situation. This static  
>> stuff smells like wants to be replaced ;-)
>
> If I knew how to do it, I would go with that direction  
> immediately. :-P

:-)

> Basically, the problem is that one wants to access Spring's  
> application context within EXTENSION's constructor. Any suggestion  
> how to do it without using static class?

Well, the only thing I could think of right now:

Define a common interface that is loaded by parent. Delegate to an  
implementation of that from EXTENSION. That should work.
But if you want to extend something that is changing (and not has a  
fix interface) you will have to load it from the RSCL.

>>> However, that would mean that one needs to modify commons-jci  
>>> project.
>> Why? How?
>
> I was thinking to enforce ResourceStoreClassLoader to load  
> everything but I know that it's not the best idea...

Well, the RCL currently is pointed to a folder of class files. It  
should not be too hard to also have it monitor a directory of jars.

cheers
--
Torsten

Re: RCL plug-in and different classloaders issues

Posted by Grzegorz Kossakowski <gr...@tuffmail.com>.
Torsten Curdt pisze:
> 
> Just a quick comment: static + classloader == evil ;-)

:-)

Yes, I thought the same but is there any other solution in scenario I outlined when it's thirdparty 
class that creates a new instance of your class, which in turn needs to access some of your resources?

>> 3. Then another class (3RDPARTY) is being loaded which is not part of 
>> my block, it's from third-party jar. It's loaded by parent classloader 
>> to ResourceStoreClassLoader. As part of configuration of this class I 
>> pass a name of class which is some kind of extension point and is 
>> implemented by class coming from my block; let's call this class 
>> EXTENSION.
>> 4. 3RDPARTY creates new instance of EXTENSION class (and this class is 
>> again not loaded by ResourceStoreClassLoader but by parent), but in 
>> EXTENSION class one tries to access field set in STATIC.
>> 5. While EXTENSION tries to access STATIC, STATIC is being loaded 
>> again, using parent classloader. The value in STATIC is gone, obviously.
>>
>> So the basic problem is that, this STATIC class is loaded by two 
>> different classloaders.
>>
>> I'm wondering if there is any kind of general solution to such 
>> problems. The only one I can think of is to enforce loading of 
>> 3RDPARTY class by ResourceStoreClassLoader so everything stays within 
>> one classloader and even reflection tricks are not dangerous.
> 
> Well, if you think about it: with this setup there is no other way 
> around to have the parent classloader know of the static class to have 
> this problem resolved. As you can't (?) modify the parent classloader 
> your only chance is to have the EXTENSION loaded by the RSCL as well.

But how this can be enforced? I mean, 3RDPARTY is loaded by parent and 3RDPARTY, when tries to 
create a new instance of EXTENSION uses it's own classloader thus uses parent. The only solution I 
can see here is that I load 3RDPARTY using classloader coming from JCI so then EXTENSION will be 
loaded with this classloader as well.

Am I missing something?

> I would take a step back and re-think the situation. This static stuff 
> smells like wants to be replaced ;-)

If I knew how to do it, I would go with that direction immediately. :-P

Basically, the problem is that one wants to access Spring's application context within EXTENSION's 
constructor. Any suggestion how to do it without using static class?

>> However, that would mean that one needs to modify commons-jci project.
> 
> Why? How?

I was thinking to enforce ResourceStoreClassLoader to load everything but I know that it's not the 
best idea...

-- 
Grzegorz Kossakowski

Re: RCL plug-in and different classloaders issues

Posted by Torsten Curdt <tc...@apache.org>.
> In brief, following steps are performed:
> 1. Class from my block is loaded using ResourceStoreClassLoader.  
> Let's call this class MAIN.
> 2. This class accesses some static method of another class loaded by  
> ResourceStoreClassLoader (because this class comes from my block as  
> well) and sets some value on static field. Let's call this class  
> STATIC

Just a quick comment: static + classloader == evil ;-)

> 3. Then another class (3RDPARTY) is being loaded which is not part  
> of my block, it's from third-party jar. It's loaded by parent  
> classloader to ResourceStoreClassLoader. As part of configuration of  
> this class I pass a name of class which is some kind of extension  
> point and is implemented by class coming from my block; let's call  
> this class EXTENSION.
> 4. 3RDPARTY creates new instance of EXTENSION class (and this class  
> is again not loaded by ResourceStoreClassLoader but by parent), but  
> in EXTENSION class one tries to access field set in STATIC.
> 5. While EXTENSION tries to access STATIC, STATIC is being loaded  
> again, using parent classloader. The value in STATIC is gone,  
> obviously.
>
> So the basic problem is that, this STATIC class is loaded by two  
> different classloaders.
>
> I'm wondering if there is any kind of general solution to such  
> problems. The only one I can think of is to enforce loading of  
> 3RDPARTY class by ResourceStoreClassLoader so everything stays  
> within one classloader and even reflection tricks are not dangerous.

Well, if you think about it: with this setup there is no other way  
around to have the parent classloader know of the static class to have  
this problem resolved. As you can't (?) modify the parent classloader  
your only chance is to have the EXTENSION loaded by the RSCL as well.

I would take a step back and re-think the situation. This static stuff  
smells like wants to be replaced ;-)

> However, that would mean that one needs to modify commons-jci project.

Why? How?

cheers
--
Torsten