IllegalAccessError - Super/sub-types loaded with differentclassloaders

Z

Zeba

Hi,

I have a use case where
- My client has a SampleBO to which he sets various values
- Needs to extend this SampleBO to ExtendedSampleBO object that
provides additional functionality.
- ExtendedSampleBO is a class that is not present in the client
application, but the client can request the framework to downloaded
and load it - USING A SEPARATE CLASSLOADER - from binary files stored
in the database.
( SampleBO is present in the client side and loaded by the normal
application classloader )

My problem is that after I get an ExtendedSampleBO object, if I try to
access the methods of the super-type (SampleBO), I get
IllegalAccessError. How do I solve this problem??!!

Re-stating my requirement - Client needs to set some values in a BO.
The framework has to provides a mechanism for dynamically extending
the functionality of the BO by using binary files deployed to the
database.

Please help!!!
Zeba
 
A

Alan Gutierrez

Zeba said:
My problem is that after I get an ExtendedSampleBO object, if I try to
access the methods of the super-type (SampleBO), I get
IllegalAccessError. How do I solve this problem??!!
Re-stating my requirement - Client needs to set some values in a BO.
The framework has to provides a mechanism for dynamically extending
the functionality of the BO by using binary files deployed to the
database.

Could it be the case that the special database reading `ClassLoader`
that loads `ExtendedSampleBO` is *not* a child of the `ClassLoader` that
loaded `SampleBO`, because if not, then the special database reading
`ClassLoader` is going to create its own `SampleBO` class and that will
be different from the application's `SampleBO` class.

I'm not sure how that would throw an `IllegalAccessError` and not a
`ClassCastException`, but it would be the first thing I'd look at.
 
Z

Zeba

Could it be the case that the special database reading `ClassLoader`
that loads `ExtendedSampleBO` is *not* a child of the `ClassLoader` that
loaded `SampleBO`, because if not, then the special database reading
`ClassLoader` is going to create its own `SampleBO` class and that will
be different from the application's `SampleBO` class.

I'm not sure how that would throw an `IllegalAccessError` and not a
`ClassCastException`, but it would be the first thing I'd look at.



Ohh :( That's the problem then. Actually the application has a large
number of Rule-set's (binary files), each of which is loaded from db
by its own classloader. However, all of these Rule-sets have a common
Master ( also loaded from db by a separate classloader ). So instead
of loading the Master binary files from the db for each of the Child-
set's, I just save a reference to the master class-loader and use that
within the Rule-set's class-loaders to load the files ( to save memory
by avoiding same classes being loaded multiple times over multiple
classloaders - there will be a large number of Rule-set's).

Is there any other solution than making the Master classloader a child
of the Rule-set classloader??

Zeba
 
Z

Zeba

Ohh :( That's the problem then. Actually the application has a large
number of Rule-set's (binary files), each of which is loaded from db
by its own classloader. However, all of these Rule-sets have a common
Master ( also loaded from db by a separate classloader ). So instead
of loading the Master binary files from the db for each of the Child-
set's, I just save a reference to the master class-loader and use that
within the Rule-set's class-loaders to load the files ( to save memory
by avoiding same classes being loaded multiple times over multiple
classloaders - there will be a large number of Rule-set's).

Is there any other solution than making the Master classloader a child
of the Rule-set classloader??

Zeba


Missed one point - ExtendedSampleBO is in the Master-set. SampleBO is
a class loaded by the parent of Rule-set's classloader.

Thanks much!
Zeba
 
L

Lew

In general, using a different classloader breaks inheritance.

Alan said:
Could it be the case that the special database reading `ClassLoader`
that loads `ExtendedSampleBO` is *not* a child of the `ClassLoader` that
loaded `SampleBO`, because if not, then the special database reading
`ClassLoader` is going to create its own `SampleBO` class and that will
be different from the application's `SampleBO` class.

Huh. I was not aware that using an inheriting classloader would fix the
loaded-class hierarchy compatibility.
 
A

Alan Gutierrez

Lew said:
In general, using a different classloader breaks inheritance.




Huh. I was not aware that using an inheriting classloader would fix the
loaded-class hierarchy compatibility.

Well, it is my understanding that their is a `ClassLoader` hierarchy.
That the child `ClassLoader` will look to its parent before loading a
class on its own, or in the case of some application container class, it
will look to the parent if it cannot find the class among its own
resources. So, by default it is parent first, then self, but for web
containers it is self first, then parent.
 
M

Mike Schilling

Lew said:
In general, using a different classloader breaks inheritance.

Which is why all classes must be loaded by the same system classloader that
loads Object :)
 
L

Lew

Lew wrote ...
Mike said:
Which is why all classes must be loaded by the same system classloader
that loads Object :)

You seem to have found one of the exceptions that breaks the "in general"
rule, thus illustrating why I said "in general" in the first place.

Perhaps I should have said, "In general, using a different classloader risks
breaking inheritance unless you plan accordingly." I foolishly thought that
was implicit in stating the general risk, but I guess some people need things
spelled out in more excruciating explicit detail than others. ;-)
 
A

Alan Gutierrez

No need to quote signatures.
Missed one point - ExtendedSampleBO is in the Master-set. SampleBO is
a class loaded by the parent of Rule-set's classloader.

You can first assert that `ClassLoader` hierarchy is the problem by
using `Class.getSuperclass` and `Class.equals` and if the `SampleBO` you
use to declare your reference is different from the `SampleBO` acting as
the super class of `ExampleSampleBO` then you do have the problem
described, and if that is not the case, then you have another problem.

There is no good alternative. You could define the methods in you BO to
return classes from the system `ClassLaoder` like the `java.util`
classes and call them via reflection, but you're well into the
wilderness, surrounded by the sun-bleached bones of the others that went
before you.

I'd say, get your `ClassLoader` hierarchy correct, or replace byte code
in the database with an interpreted language like Groovy or jRuby. If it
were me, I'd express my logic in Java and deploy the generated byte code
in JARs. I'm a traditionalist in this way.
 
L

Lew

Zeba said:
Ohh :( That's the problem then. Actually the application has a large
number of Rule-set's [sic] (binary files), each of which is loaded from db
by its own classloader. However, all of these Rule-sets have a common

Why use separate classloaders?
Master ( also loaded from db by a separate classloader ). So instead
of loading the Master binary files from the db for each of the Child-
set's, I just save a reference to the master class-loader and use that
within the Rule-set's [sic] class-loaders to load the files ( to save memory
by avoiding same classes being loaded multiple times over multiple
classloaders - there will be a large number of Rule-set's [sic]).

Another way to save that memory is not to use separate classloaders. What
other consequences would that cause?
Is there any other solution than making the Master classloader a child
of the Rule-set classloader??

Don't use separate classloaders?
 
M

Mike Schilling

Lew said:
Lew wrote ...



You seem to have found one of the exceptions that breaks the "in general"
rule, thus illustrating why I said "in general" in the first place.

Perhaps I should have said, "In general, using a different classloader
risks breaking inheritance unless you plan accordingly." I foolishly
thought that was implicit in stating the general risk, but I guess some
people need things spelled out in more excruciating explicit detail than
others. ;-)

In fact, all non-system classes have ancestors from the system classloader,
but you know that.

From what I've seen, subclassing in a child classloader is quite safe [1].
What risks are you warning about?

1. Though implementing an interface in a child classloader is an even better
idea.
 
A

Alan Gutierrez

Alan said:
No need to quote signatures.


You can first assert that `ClassLoader` hierarchy is the problem by
using `Class.getSuperclass` and `Class.equals` and if the `SampleBO` you
use to declare your reference is different from the `SampleBO` acting as
the super class of `ExampleSampleBO` then you do have the problem
described, and if that is not the case, then you have another problem.

There is no good alternative. You could define the methods in you BO to
return classes from the system `ClassLaoder` like the `java.util`
classes and call them via reflection, but you're well into the
wilderness, surrounded by the sun-bleached bones of the others that went
before you.

I'd say, get your `ClassLoader` hierarchy correct, or replace byte code
in the database with an interpreted language like Groovy or jRuby. If it
were me, I'd express my logic in Java and deploy the generated byte code
in JARs. I'm a traditionalist in this way.

Hmm... It occurs to me that I'm imagining that you've put byte code in
the database, which upon re-reading the description of your system,
doesn't jibe. If you need to transfer objects between processes, use a
form of serialization?
 
L

Lew

Lew wrote ...
Or by children thereof, in a parent-first order, so that the classes are in
fact loaded by the same loader, not by children of the one that loads
'Object'. I guess. I'm still learning how classloaders work.

Lew wrote ...
Mike said:
In fact, all non-system classes have ancestors from the system
classloader, but you know that.

From what I've seen, subclassing in a child classloader is quite safe
[1]. What risks are you warning about?

If the classloader is not a child of the one that loaded the putative parent
class, then the putative child class will not inherit properly. As pointed
out upthread, app servers are known to reverse classloader order to
child-first loading, so in such an environment you can break hierarchies in
loaded classes. I've seen it happen.

The situation is exacerbated by JAR hell. You can load instances of a
particular class from incompatible JAR versions. I've seen that happen, too.

I'm not sure that child-first classloading preserves hierarchies even when the
classloader's parent loads the target class's parent. The rules state that
each classloader forms its own namespace, so in a child-first situation you
can load, say, log4j's 'Category' as the parent of its 'Logger' with one
classloader, and the same classes separately through another loader, and the
upcast 'Category categ = someLogger' would therefore fail if in that moment
you somehow crossed classloaders.
 
L

Lew

Lew wrote: ...
Lew wrote: ...
Or by children thereof, in a parent-first order, so that the classes are
in fact loaded by the same loader, not by children of the one that loads
'Object'. I guess. I'm still learning how classloaders work. ...
Mike said:
In fact, all non-system classes have ancestors from the system
classloader, but you know that.

From what I've seen, subclassing in a child classloader is quite safe
[1]. What risks are you warning about?

Lew wrote: ...
If the classloader is not a child of the one that loaded the putative
parent class, then the putative child class will not inherit properly.
As pointed out upthread, app servers are known to reverse classloader
order to child-first loading, so in such an environment you can break
hierarchies in loaded classes. I've seen it happen.

The situation is exacerbated by JAR hell. You can load instances of a
particular class from incompatible JAR versions. I've seen that happen,
too.

I'm not sure that child-first classloading preserves hierarchies even
when the classloader's parent loads the target class's parent. The rules
state that each classloader forms its own namespace, so in a child-first
situation you can load, say, log4j's 'Category' as the parent of its
'Logger' with one classloader, and the same classes separately through
another loader, and the upcast 'Category categ = someLogger' would
therefore fail if in that moment you somehow crossed classloaders.

<http://articles.qos.ch/classloader.html>
shows how inheritance can be broken through classloader abuse.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,778
Messages
2,569,605
Members
45,238
Latest member
Top CryptoPodcasts

Latest Threads

Top