You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by "Jackson, Bruce" <br...@qualcomm.com> on 2008/08/01 16:01:40 UTC

Classloading across bundles

Here's a question:

I have a utility class in a bundle which will generate a dynamic proxy as a
service to other bundles running inside Felix. Lets call this bundle "A".

Is this possible in Felix/OSGi without having having to explicitly declare
the import of the interface over which A will operate?

Thanks

Bruce


RE: Classloading across bundles

Posted by Craig Phillips <lc...@praxiseng.com>.
Hi,

Not that I'm doing anything other than slightly venting myself, with no
intentional bashing of any kind (other than maybe the whole class
loading invention in java, more or less)...

Those Class.forName() constructs seem to be a constant source of
frustration, especially when coupled to things like OSGi (not the fault
of OSGi in the least, IMO); I just ran into an issue with
Class.forName() when it came to loading MySql drivers... I ended up
added the MySql driver package(s) to the bootdelegation property in the
Felix config.properties file and problem solved (ok, maybe it's not
esoteric optimalism, admittedly; And, that thwarts a dynamic upgrade of
the drivers, but still...);

With OSGi, it's such a mind set change from "legacy container business
as usual" and all these Class.forName() games of the past -- to service
injection, really... I'd rather play the "service injection" game
myself, frankly...

Well, glad to see some closure on this one...   Have a good day, happy
trails, Craig Phillips, Praxis

-----Original Message-----
From: Jackson, Bruce [mailto:brucej@qualcomm.com] 
Sent: Monday, August 04, 2008 10:08 AM
To: dev@felix.apache.org
Subject: Re: Classloading across bundles

Thanks for that, I've got to the bottom of the problem.
Its quite obscure: obviously, my handler does many other things and
contains a helper which in the constructor stores a copy of the class
name.
In the invoke, the stored class name is used in a Class.forName() call,
and that is what causes the exception.

Thanks for your help, much appreciated


On 04/08/2008 11:38, "Stuart McCulloch" <st...@jayway.net>
wrote:

2008/8/4 Jackson, Bruce <br...@qualcomm.com>

> Hi Stuart
>
> Well, that's interesting. To use your description of my problem (which
is
> correct) the interface ObjectManagement declared in bundle A is indeed
> public, and it is also imported by B. B provides its own interface (in
the
> code fragment, its passed as the argument clazz) which it passes to
the
> service method in A.
>

I've just hacked up an extremely simple project that does exactly this:

  the client (B) passes a class to the proxy service (A), which creates
  a proxy based on the given class and another interface from A that
  is both public and exported from A.

The project deploys and runs without any exceptions - also note the
proxy bundle (A) doesn't need to import anything from the client (B).

So I think there must be something else in your particular setup that
is causing the visibility issue - I see from the stack trace that you're
also using some sort of remoting, which does a "Class.forName(...)"
I think this is the actual problem, to confirm this you could comment
out the remoting call and see if the same exception occurs.

To diagnose further we'd need access to some sort of public testcase
(unless your project is already open-source) that recreates the issue,
because the solution depends a lot on what the remoting code needs.

I'll email you my example proxy project separately, as attachments
often get removed from the mailing list - to build and deploy it use:

   "mvn clean install pax:provision"

HTH

So, according to your scenario, A should be able to create a proxy
object
> with interfaces ObjectManagement (from A) and clazz (from B).
> Running the code, it does actually appear that this works: I do get an
> object returned from the call to the factory in B (I can see it in
Eclipse's
> debugger, including an InvocationHandler instance that looks ok):
>
> Song s = (Song) ObjectFactory.getObject(Song.class, true);
>
> However, as soon as I try to invoke methods on the object s, I get
> exceptions, for example:
>
> Song s = (Song) ObjectFactory.getObject(Song.class, true); if(s ==
null) {
>
>    System.err.println("!!! NULL");
>
> } System.out.println("s: " + s.toString());
>
> ...the code creates the object s, it DOESN'T print "!!!NULL" but as
soon as
> it gets to s.toString() (and I've tried this with other methods
declared in
> Song too) I get:
>
> java.lang.reflect.UndeclaredThrowableException    at
> $Proxy5.toString(Unknown Source)    at
>
com.qualcomm.zoom.itunes.LibraryHandler.endElement(LibraryHandler.java:7
7)
> Caused by: java.lang.ClassNotFoundException:
com.qualcomm.zoom.itunes.Song
>    at java.lang.ClassLoader.findClass(ClassLoader.java:413)    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:316)    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at
>
org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(
BundleLoader.java:429)
>    at
>
org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLo
ader.java:369)
>    at
>
org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLo
ader.java:357)
>    at
>
org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(Defau
ltClassLoader.java:83)
>    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at
> java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)    at
> java.lang.Class.forName0(Native Method)    at
> java.lang.Class.forName(Class.java:164)    at
> com.qualcomm.pf.p2.remoting.Invoker.invoke(Invoker.java:145)
>
> This looks like its the InvocationHandler that can't see the class
> declaration but that's also in the package exported by A, so I'm
confused?!
>

--
Cheers, Stuart


Re: Classloading across bundles

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Thanks for that, I've got to the bottom of the problem.
Its quite obscure: obviously, my handler does many other things and contains a helper which in the constructor stores a copy of the class name.
In the invoke, the stored class name is used in a Class.forName() call, and that is what causes the exception.

Thanks for your help, much appreciated


On 04/08/2008 11:38, "Stuart McCulloch" <st...@jayway.net> wrote:

2008/8/4 Jackson, Bruce <br...@qualcomm.com>

> Hi Stuart
>
> Well, that's interesting. To use your description of my problem (which is
> correct) the interface ObjectManagement declared in bundle A is indeed
> public, and it is also imported by B. B provides its own interface (in the
> code fragment, its passed as the argument clazz) which it passes to the
> service method in A.
>

I've just hacked up an extremely simple project that does exactly this:

  the client (B) passes a class to the proxy service (A), which creates
  a proxy based on the given class and another interface from A that
  is both public and exported from A.

The project deploys and runs without any exceptions - also note the
proxy bundle (A) doesn't need to import anything from the client (B).

So I think there must be something else in your particular setup that
is causing the visibility issue - I see from the stack trace that you're
also using some sort of remoting, which does a "Class.forName(...)"
I think this is the actual problem, to confirm this you could comment
out the remoting call and see if the same exception occurs.

To diagnose further we'd need access to some sort of public testcase
(unless your project is already open-source) that recreates the issue,
because the solution depends a lot on what the remoting code needs.

I'll email you my example proxy project separately, as attachments
often get removed from the mailing list - to build and deploy it use:

   "mvn clean install pax:provision"

HTH

So, according to your scenario, A should be able to create a proxy object
> with interfaces ObjectManagement (from A) and clazz (from B).
> Running the code, it does actually appear that this works: I do get an
> object returned from the call to the factory in B (I can see it in Eclipse's
> debugger, including an InvocationHandler instance that looks ok):
>
> Song s = (Song) ObjectFactory.getObject(Song.class, true);
>
> However, as soon as I try to invoke methods on the object s, I get
> exceptions, for example:
>
> Song s = (Song) ObjectFactory.getObject(Song.class, true); if(s == null) {
>
>    System.err.println("!!! NULL");
>
> } System.out.println("s: " + s.toString());
>
> ...the code creates the object s, it DOESN'T print "!!!NULL" but as soon as
> it gets to s.toString() (and I've tried this with other methods declared in
> Song too) I get:
>
> java.lang.reflect.UndeclaredThrowableException    at
> $Proxy5.toString(Unknown Source)    at
> com.qualcomm.zoom.itunes.LibraryHandler.endElement(LibraryHandler.java:77)
> Caused by: java.lang.ClassNotFoundException: com.qualcomm.zoom.itunes.Song
>    at java.lang.ClassLoader.findClass(ClassLoader.java:413)    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:316)    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at
> org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:429)
>    at
> org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:369)
>    at
> org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:357)
>    at
> org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)
>    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at
> java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)    at
> java.lang.Class.forName0(Native Method)    at
> java.lang.Class.forName(Class.java:164)    at
> com.qualcomm.pf.p2.remoting.Invoker.invoke(Invoker.java:145)
>
> This looks like its the InvocationHandler that can't see the class
> declaration but that's also in the package exported by A, so I'm confused?!
>

--
Cheers, Stuart


Re: Classloading across bundles and DynamicImport-package

Posted by Karl Pauls <ka...@gmail.com>.

Am 07.08.2008 um 18:09 schrieb "Stuart McCulloch" <stuart.mcculloch@jayway.net 
 >:

> 2008/8/7 Jackson, Bruce <br...@qualcomm.com>
>
>> Its not exactly a legacy situation. The problem I have is one  
>> that's shared
>> with many object persistence frameworks that would naturally  
>> provide that
>> capability as a service in an OSGi environment.
>>
>> In my case, the persistence model is based on the ability of any  
>> bundle to
>> declare an interface which is suitably annotated, and which the  
>> persistence
>> service will automatically construct suitable tables, views etc  
>> based on the
>> interface methods, arguments and annotations. An object factory in  
>> the
>> provider then generates a "real" object usable in the caller  
>> bundle, and
>> whose methods are interpreted by a dynamic proxy into calls to the
>> persistence layer.
>>
>> The problem comes when you wish to extract information from the  
>> persistence
>> service. How do you recreate the stored object when the interface  
>> which was
>> used to create the dynamic proxy is not in the persistence layer's  
>> bundle?
>>
>
> one possible solution that would work with all the current  
> frameworks is to
> use a service to get the interface class - based on something unique  
> in the
> persisted object like the interface name or serialization id
>
> client bundles would register service implementations, which return  
> any
> interface class(es) they know of that match the request. The  
> persistence
> bundle can then iterate over the available services until it finds  
> one that
> can supply the necessary runtime class (or it could use filters to  
> avoid
> iterating)
>
> alternatively... client bundles could register services to recreate  
> actual
> objects based on given data / schema.
>
> a lot of the classloading issues in OSGi can disappear when you use  
> services
> to delegate tasks to the bundles that have the required knowledge.  
> The hard
> part is deciding what to use services for, and what functionality to  
> push
> into which bundle - but you can often use standard OO techniques  
> like CRC
> cards to help brainstorm ideas
>
> imho, services are the best kept secret of OSGi...

+1

regards,

Karl

>
> On 07/08/2008 15:31, "Richard S. Hall" <he...@ungoverned.org> wrote:
>>
>> Jackson, Bruce wrote:
>>> Does Felix support anything that carries out a similar function to  
>>> buddy
>> class loading in Equinox?
>>> I'm aware of the DynamicImport-Package, but that rather supposes  
>>> that the
>> bundle who declares this knows the bundles that it needs as  
>> "helpers" to
>> load classes.
>>>
>>
>> Sorry, no, Felix does not support any such option. And you are right,
>> dynamic imports are probably not exactly what you want either.
>> Currently, it is possible that the spec will eventually define  
>> something
>> like this, but currently there is nothing. However, this should  
>> likely
>> only be used in legacy situations, is that your situation?
>>
>> -> richard
>>
>>
>
>
> -- 
> Cheers, Stuart

Re: Classloading across bundles and DynamicImport-package

Posted by Stuart McCulloch <st...@jayway.net>.
2008/8/7 Jackson, Bruce <br...@qualcomm.com>

> Its not exactly a legacy situation. The problem I have is one that's shared
> with many object persistence frameworks that would naturally provide that
> capability as a service in an OSGi environment.
>
> In my case, the persistence model is based on the ability of any bundle to
> declare an interface which is suitably annotated, and which the persistence
> service will automatically construct suitable tables, views etc based on the
> interface methods, arguments and annotations. An object factory in the
> provider then generates a "real" object usable in the caller bundle, and
> whose methods are interpreted by a dynamic proxy into calls to the
> persistence layer.
>
> The problem comes when you wish to extract information from the persistence
> service. How do you recreate the stored object when the interface which was
> used to create the dynamic proxy is not in the persistence layer's bundle?
>

one possible solution that would work with all the current frameworks is to
use a service to get the interface class - based on something unique in the
persisted object like the interface name or serialization id

client bundles would register service implementations, which return any
interface class(es) they know of that match the request. The persistence
bundle can then iterate over the available services until it finds one that
can supply the necessary runtime class (or it could use filters to avoid
iterating)

alternatively... client bundles could register services to recreate actual
objects based on given data / schema.

a lot of the classloading issues in OSGi can disappear when you use services
to delegate tasks to the bundles that have the required knowledge. The hard
part is deciding what to use services for, and what functionality to push
into which bundle - but you can often use standard OO techniques like CRC
cards to help brainstorm ideas

imho, services are the best kept secret of OSGi...

On 07/08/2008 15:31, "Richard S. Hall" <he...@ungoverned.org> wrote:
>
> Jackson, Bruce wrote:
> > Does Felix support anything that carries out a similar function to buddy
> class loading in Equinox?
> > I'm aware of the DynamicImport-Package, but that rather supposes that the
> bundle who declares this knows the bundles that it needs as "helpers" to
> load classes.
> >
>
> Sorry, no, Felix does not support any such option. And you are right,
> dynamic imports are probably not exactly what you want either.
> Currently, it is possible that the spec will eventually define something
> like this, but currently there is nothing. However, this should likely
> only be used in legacy situations, is that your situation?
>
> -> richard
>
>


-- 
Cheers, Stuart

Re: Classloading across bundles and DynamicImport-package

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Its not exactly a legacy situation. The problem I have is one that's shared with many object persistence frameworks that would naturally provide that capability as a service in an OSGi environment.

In my case, the persistence model is based on the ability of any bundle to declare an interface which is suitably annotated, and which the persistence service will automatically construct suitable tables, views etc based on the interface methods, arguments and annotations. An object factory in the provider then generates a "real" object usable in the caller bundle, and whose methods are interpreted by a dynamic proxy into calls to the persistence layer.

The problem comes when you wish to extract information from the persistence service. How do you recreate the stored object when the interface which was used to create the dynamic proxy is not in the persistence layer's bundle?


On 07/08/2008 15:31, "Richard S. Hall" <he...@ungoverned.org> wrote:

Jackson, Bruce wrote:
> Does Felix support anything that carries out a similar function to buddy class loading in Equinox?
> I'm aware of the DynamicImport-Package, but that rather supposes that the bundle who declares this knows the bundles that it needs as "helpers" to load classes.
>

Sorry, no, Felix does not support any such option. And you are right,
dynamic imports are probably not exactly what you want either.
Currently, it is possible that the spec will eventually define something
like this, but currently there is nothing. However, this should likely
only be used in legacy situations, is that your situation?

-> richard


Re: Classloading across bundles and DynamicImport-package

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Jackson, Bruce wrote:
> Does Felix support anything that carries out a similar function to buddy class loading in Equinox?
> I'm aware of the DynamicImport-Package, but that rather supposes that the bundle who declares this knows the bundles that it needs as "helpers" to load classes.
>   

Sorry, no, Felix does not support any such option. And you are right, 
dynamic imports are probably not exactly what you want either. 
Currently, it is possible that the spec will eventually define something 
like this, but currently there is nothing. However, this should likely 
only be used in legacy situations, is that your situation?

-> richard

Classloading across bundles and DynamicImport-package

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Does Felix support anything that carries out a similar function to buddy class loading in Equinox?
I'm aware of the DynamicImport-Package, but that rather supposes that the bundle who declares this knows the bundles that it needs as "helpers" to load classes.

Classloading across bundles

Posted by Stuart McCulloch <st...@jayway.net>.
2008/8/4 Jackson, Bruce <br...@qualcomm.com>

> Hi Stuart
>
> Well, that's interesting. To use your description of my problem (which is
> correct) the interface ObjectManagement declared in bundle A is indeed
> public, and it is also imported by B. B provides its own interface (in the
> code fragment, its passed as the argument clazz) which it passes to the
> service method in A.
>

I've just hacked up an extremely simple project that does exactly this:

  the client (B) passes a class to the proxy service (A), which creates
  a proxy based on the given class and another interface from A that
  is both public and exported from A.

The project deploys and runs without any exceptions - also note the
proxy bundle (A) doesn't need to import anything from the client (B).

So I think there must be something else in your particular setup that
is causing the visibility issue - I see from the stack trace that you're
also using some sort of remoting, which does a "Class.forName(...)"
I think this is the actual problem, to confirm this you could comment
out the remoting call and see if the same exception occurs.

To diagnose further we'd need access to some sort of public testcase
(unless your project is already open-source) that recreates the issue,
because the solution depends a lot on what the remoting code needs.

I'll email you my example proxy project separately, as attachments
often get removed from the mailing list - to build and deploy it use:

   "mvn clean install pax:provision"

HTH

So, according to your scenario, A should be able to create a proxy object
> with interfaces ObjectManagement (from A) and clazz (from B).
> Running the code, it does actually appear that this works: I do get an
> object returned from the call to the factory in B (I can see it in Eclipse's
> debugger, including an InvocationHandler instance that looks ok):
>
> Song s = (Song) ObjectFactory.getObject(Song.class, true);
>
> However, as soon as I try to invoke methods on the object s, I get
> exceptions, for example:
>
> Song s = (Song) ObjectFactory.getObject(Song.class, true); if(s == null) {
>
>    System.err.println("!!! NULL");
>
> } System.out.println("s: " + s.toString());
>
> ...the code creates the object s, it DOESN'T print "!!!NULL" but as soon as
> it gets to s.toString() (and I've tried this with other methods declared in
> Song too) I get:
>
> java.lang.reflect.UndeclaredThrowableException    at
> $Proxy5.toString(Unknown Source)    at
> com.qualcomm.zoom.itunes.LibraryHandler.endElement(LibraryHandler.java:77)
> Caused by: java.lang.ClassNotFoundException: com.qualcomm.zoom.itunes.Song
>    at java.lang.ClassLoader.findClass(ClassLoader.java:413)    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:316)    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at
> org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:429)
>    at
> org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:369)
>    at
> org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:357)
>    at
> org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)
>    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at
> java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)    at
> java.lang.Class.forName0(Native Method)    at
> java.lang.Class.forName(Class.java:164)    at
> com.qualcomm.pf.p2.remoting.Invoker.invoke(Invoker.java:145)
>
> This looks like its the InvocationHandler that can't see the class
> declaration but that's also in the package exported by A, so I'm confused?!
>

-- 
Cheers, Stuart

Re: Classloading across bundles

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Hi Stuart

Well, that's interesting. To use your description of my problem (which is correct) the interface ObjectManagement declared in bundle A is indeed public, and it is also imported by B. B provides its own interface (in the code fragment, its passed as the argument clazz) which it passes to the service method in A.

So, according to your scenario, A should be able to create a proxy object with interfaces ObjectManagement (from A) and clazz (from B).
Running the code, it does actually appear that this works: I do get an object returned from the call to the factory in B (I can see it in Eclipse's debugger, including an InvocationHandler instance that looks ok):

Song s = (Song) ObjectFactory.getObject(Song.class, true);

However, as soon as I try to invoke methods on the object s, I get exceptions, for example:

Song s = (Song) ObjectFactory.getObject(Song.class, true); if(s == null) {

    System.err.println("!!! NULL");

} System.out.println("s: " + s.toString());

...the code creates the object s, it DOESN'T print "!!!NULL" but as soon as it gets to s.toString() (and I've tried this with other methods declared in Song too) I get:

java.lang.reflect.UndeclaredThrowableException    at $Proxy5.toString(Unknown Source)    at com.qualcomm.zoom.itunes.LibraryHandler.endElement(LibraryHandler.java:77)
Caused by: java.lang.ClassNotFoundException: com.qualcomm.zoom.itunes.Song    at java.lang.ClassLoader.findClass(ClassLoader.java:413)    at java.lang.ClassLoader.loadClass(ClassLoader.java:316)    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:429)    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:369)    at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:357)    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:83)    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)    at java.lang.Class.forName0(Native Method)    at java.lang.Class.forName(Class.java:164)    at com.qualcomm.pf.p2.remoting.Invoker.invoke(Invoker.java:145)

This looks like its the InvocationHandler that can't see the class declaration but that's also in the package exported by A, so I'm confused?!


On 01/08/2008 17:12, "Stuart McCulloch" <st...@jayway.net> wrote:

2008/8/1 Jackson, Bruce <br...@qualcomm.com>

> Yes, the code in ObjectFactory is basically:
>
> public static Object getObject(Class clazz) {
>
>    ...
>    obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz,
> ObjectManagement.class}, new Invoker(clazz, id, tableName));
>    ...
>    return obj;
> }
>
> That's throws a ClassNotFoundException, I assume, because clazz (declared
> in B and not imported explicitly in A) is not loadable from with A.
>

I have some recent experience with this situation...

say you have a bundle A that creates proxies based on classes
from A and classes passed in from client bundles (B, C, D...)

if the classes used from A are all public, and are imported by all
the client bundles then you should be ok using the classloaders
from those client classes, because their classloaders are able to
see both public A classes and their own client classes (B, etc.).

However, if the proxy needs to see private classes from A then
you can't use the client classloaders because they cannot see
any of the private A classes

One option is then to add a "DynamicImport-Package: *" entry
to the manifest of A, and use A's classloader to create the proxy.
The DynamicImport-Package wildcard will dynamically add any
public packages from B, C, D, etc to A as required

A's classloader can then see its own classes and any public
client classes that it needs - however, this can cause leakage
of classes because once a class is in A's classloader, it can
be seen by any of the generated proxies.

Also, this won't work if the class passed in by the client bundle
is private to the client, because it's not available to be imported.

Another solution is to use a custom classloader to try to bridge
the two class spaces - the proxy bundle and the client bundle -
into one space which is then used by the generated proxy.

One such classloader is Equinox's ContextFinder, which looks
at the call stack to determine which classloader to load a class.
However, this is complex and may be overkill for this situation.

A simpler approach is used in the latest Guice code - we have
a very basic switch to delegate either to the client classloader
or the proxy bundle classloader.

note: you have to be careful when using a custom classloader
to proxy package-private classes, because the generated class
cannot access package-private classes in another classloader

more information about the Guice approach is available here:

   http://code.google.com/p/google-guice/wiki/BytecodeGeneration

and a similar approach is discussed here:

   http://techblog.andypiper.com/2008/07/classloader-hell-osgi-way.html

the actual Guice code to handle the bridging can be found here:


http://google-guice.googlecode.com/svn/trunk/src/com/google/inject/internal/BytecodeGen.java

we're also thinking about contributing this code back to CGLIB.

one last piece of advice - when debugging OSGi classloader
issues, you might find it useful to draw out the bundles and
mark what each exports/imports - you can then see whether
any classloader has access to all the necessary classes.

if no classloader has enough access, and you can't arrange
it via explicit imports, or implicit dynamic imports then you'll
need to use some sort of bridging approach.

HTH - apologies for the long email, got a bit carried away ;)

On 01/08/2008 16:25, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>
> Do you use Proxy.newProxyInstance?
> The first param of this method is a class loader. So, what is the
> value you use for that param? In my view you should use the
> clazz.getClassLoader that is equal with the class loader that loaded
> Foo.
> And it should not matter that you export or not the the package that
> contains Foo.
>
> On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com>
> wrote:
> > I'm not passing any classloader with my class, just the object Foo.class.
> >
> > The issue is that bundle B (which is the caller to ObjectFactory declared
> in A) does not export Foo.class, and thus the class loader in A can't see
> it.
> > Now that's well, and good for most cases since I can always export the
> package that Foo.class is contained within, and import it in bundle A, but
> in this case, ObjectFactory becomes rather useless since its trying to offer
> a generic facility.
> >
> > I've tried getting the classloader of Foo.class, but that fails in the
> same way with a ClassNotFoundException. I could go through the pain in B of
> getting the bytes that make up the class, passing them to ObjectFactory and
> then doing a defineClass() there, but that seems to be very complex.
> >
> >
> > On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
> >
> > What class loader are you pasing to Proxy.newProxyInstance? You should
> > pass the one of the class you send as parameter so in your case
> > clazz.getClassLoader.
> >
> > On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com>
> wrote:
> >> Sorry, I don't think I made myself particularly clear:
> >>
> >> I have a bundle "A" which exports a package containing a class
> (ObjectFactory.class) with the method:
> >>
> >> public static Object getObject(Class clazz);
> >>
> >> This method creates a dynamic proxy object to be returned to the caller.
> >> I have bundles B, C, and D which wish to make use of this class, and
> which will call it passing an interface, for example:
> >>
> >> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
> >>
> >> However, ObjectFactory throws a ClassNotFoundException because Foo.class
> is not in the import list for bundle A. Is there a way of allowing this?
> >>
> >>
> >> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
> >>
> >> Jackson, Bruce wrote:
> >>> Here's a question:
> >>>
> >>> I have a utility class in a bundle which will generate a dynamic proxy
> as a
> >>> service to other bundles running inside Felix. Lets call this bundle
> "A".
> >>>
> >>> Is this possible in Felix/OSGi without having having to explicitly
> declare
> >>> the import of the interface over which A will operate?
> >>>
> >>
> >> Well, you can get access to the interface class definition by calling
> >> Bundle.loadClass() on bundle A without importing from A, so then you
> >> should be able to use that to create the proxy, I would imagine.
> >>
> >> -> richard
> >>
> >>> Thanks
> >>>
> >>> Bruce
> >>>
> >>>
> >>
> >>
> >
> >
> >
> > --
> > Alin Dreghiciu
> > http://www.ops4j.org - New Energy for OSS Communities - Open
> > Participation Software.
> > http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> > http://malaysia.jayway.net - New Energy for Projects - Great People
> > working on Great Projects at Great Places
> >
> >
>
>
>
> --
> Alin Dreghiciu
> http://www.ops4j.org - New Energy for OSS Communities - Open
> Participation Software.
> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> http://malaysia.jayway.net - New Energy for Projects - Great People
> working on Great Projects at Great Places
>
>


--
Cheers, Stuart


Re: Classloading across bundles

Posted by Stuart McCulloch <st...@jayway.net>.
2008/8/1 Jackson, Bruce <br...@qualcomm.com>

> Yes, the code in ObjectFactory is basically:
>
> public static Object getObject(Class clazz) {
>
>    ...
>    obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz,
> ObjectManagement.class}, new Invoker(clazz, id, tableName));
>    ...
>    return obj;
> }
>
> That's throws a ClassNotFoundException, I assume, because clazz (declared
> in B and not imported explicitly in A) is not loadable from with A.
>

I have some recent experience with this situation...

say you have a bundle A that creates proxies based on classes
from A and classes passed in from client bundles (B, C, D...)

if the classes used from A are all public, and are imported by all
the client bundles then you should be ok using the classloaders
from those client classes, because their classloaders are able to
see both public A classes and their own client classes (B, etc.).

However, if the proxy needs to see private classes from A then
you can't use the client classloaders because they cannot see
any of the private A classes

One option is then to add a "DynamicImport-Package: *" entry
to the manifest of A, and use A's classloader to create the proxy.
The DynamicImport-Package wildcard will dynamically add any
public packages from B, C, D, etc to A as required

A's classloader can then see its own classes and any public
client classes that it needs - however, this can cause leakage
of classes because once a class is in A's classloader, it can
be seen by any of the generated proxies.

Also, this won't work if the class passed in by the client bundle
is private to the client, because it's not available to be imported.

Another solution is to use a custom classloader to try to bridge
the two class spaces - the proxy bundle and the client bundle -
into one space which is then used by the generated proxy.

One such classloader is Equinox's ContextFinder, which looks
at the call stack to determine which classloader to load a class.
However, this is complex and may be overkill for this situation.

A simpler approach is used in the latest Guice code - we have
a very basic switch to delegate either to the client classloader
or the proxy bundle classloader.

note: you have to be careful when using a custom classloader
to proxy package-private classes, because the generated class
cannot access package-private classes in another classloader

more information about the Guice approach is available here:

   http://code.google.com/p/google-guice/wiki/BytecodeGeneration

and a similar approach is discussed here:

   http://techblog.andypiper.com/2008/07/classloader-hell-osgi-way.html

the actual Guice code to handle the bridging can be found here:


http://google-guice.googlecode.com/svn/trunk/src/com/google/inject/internal/BytecodeGen.java

we're also thinking about contributing this code back to CGLIB.

one last piece of advice - when debugging OSGi classloader
issues, you might find it useful to draw out the bundles and
mark what each exports/imports - you can then see whether
any classloader has access to all the necessary classes.

if no classloader has enough access, and you can't arrange
it via explicit imports, or implicit dynamic imports then you'll
need to use some sort of bridging approach.

HTH - apologies for the long email, got a bit carried away ;)

On 01/08/2008 16:25, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>
> Do you use Proxy.newProxyInstance?
> The first param of this method is a class loader. So, what is the
> value you use for that param? In my view you should use the
> clazz.getClassLoader that is equal with the class loader that loaded
> Foo.
> And it should not matter that you export or not the the package that
> contains Foo.
>
> On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com>
> wrote:
> > I'm not passing any classloader with my class, just the object Foo.class.
> >
> > The issue is that bundle B (which is the caller to ObjectFactory declared
> in A) does not export Foo.class, and thus the class loader in A can't see
> it.
> > Now that's well, and good for most cases since I can always export the
> package that Foo.class is contained within, and import it in bundle A, but
> in this case, ObjectFactory becomes rather useless since its trying to offer
> a generic facility.
> >
> > I've tried getting the classloader of Foo.class, but that fails in the
> same way with a ClassNotFoundException. I could go through the pain in B of
> getting the bytes that make up the class, passing them to ObjectFactory and
> then doing a defineClass() there, but that seems to be very complex.
> >
> >
> > On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
> >
> > What class loader are you pasing to Proxy.newProxyInstance? You should
> > pass the one of the class you send as parameter so in your case
> > clazz.getClassLoader.
> >
> > On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com>
> wrote:
> >> Sorry, I don't think I made myself particularly clear:
> >>
> >> I have a bundle "A" which exports a package containing a class
> (ObjectFactory.class) with the method:
> >>
> >> public static Object getObject(Class clazz);
> >>
> >> This method creates a dynamic proxy object to be returned to the caller.
> >> I have bundles B, C, and D which wish to make use of this class, and
> which will call it passing an interface, for example:
> >>
> >> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
> >>
> >> However, ObjectFactory throws a ClassNotFoundException because Foo.class
> is not in the import list for bundle A. Is there a way of allowing this?
> >>
> >>
> >> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
> >>
> >> Jackson, Bruce wrote:
> >>> Here's a question:
> >>>
> >>> I have a utility class in a bundle which will generate a dynamic proxy
> as a
> >>> service to other bundles running inside Felix. Lets call this bundle
> "A".
> >>>
> >>> Is this possible in Felix/OSGi without having having to explicitly
> declare
> >>> the import of the interface over which A will operate?
> >>>
> >>
> >> Well, you can get access to the interface class definition by calling
> >> Bundle.loadClass() on bundle A without importing from A, so then you
> >> should be able to use that to create the proxy, I would imagine.
> >>
> >> -> richard
> >>
> >>> Thanks
> >>>
> >>> Bruce
> >>>
> >>>
> >>
> >>
> >
> >
> >
> > --
> > Alin Dreghiciu
> > http://www.ops4j.org - New Energy for OSS Communities - Open
> > Participation Software.
> > http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> > http://malaysia.jayway.net - New Energy for Projects - Great People
> > working on Great Projects at Great Places
> >
> >
>
>
>
> --
> Alin Dreghiciu
> http://www.ops4j.org - New Energy for OSS Communities - Open
> Participation Software.
> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> http://malaysia.jayway.net - New Energy for Projects - Great People
> working on Great Projects at Great Places
>
>


-- 
Cheers, Stuart

Re: Classloading across bundles

Posted by Alin Dreghiciu <ad...@gmail.com>.
Yes, I was on the point to say that. This is from JavaDoc of Proxy:

"All of the interface types must be visible by name through the
specified class loader."

You may try to define your own class loader that will delegate to the
class loader of clazz and use as parent the class loader of the bundle
that defines the ObjectManagement. But you are on mined ground.

On Fri, Aug 1, 2008 at 5:51 PM, Karl Pauls <ka...@gmail.com> wrote:
> my guess would be it's the objectmanagment class that can not be found by
> the classloader of the Foo class :-)
>
> regards,
>
> Karl
>
> Am 01.08.2008 um 17:31 schrieb "Jackson, Bruce" <br...@qualcomm.com>:
>
>> Yes, the code in ObjectFactory is basically:
>>
>> public static Object getObject(Class clazz) {
>>
>>   ...
>>   obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz,
>> ObjectManagement.class}, new Invoker(clazz, id, tableName));
>>   ...
>>   return obj;
>> }
>>
>> That's throws a ClassNotFoundException, I assume, because clazz (declared
>> in B and not imported explicitly in A) is not loadable from with A.
>>
>> On 01/08/2008 16:25, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>>
>> Do you use Proxy.newProxyInstance?
>> The first param of this method is a class loader. So, what is the
>> value you use for that param? In my view you should use the
>> clazz.getClassLoader that is equal with the class loader that loaded
>> Foo.
>> And it should not matter that you export or not the the package that
>> contains Foo.
>>
>> On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com>
>> wrote:
>>>
>>> I'm not passing any classloader with my class, just the object Foo.class.
>>>
>>> The issue is that bundle B (which is the caller to ObjectFactory declared
>>> in A) does not export Foo.class, and thus the class loader in A can't see
>>> it.
>>> Now that's well, and good for most cases since I can always export the
>>> package that Foo.class is contained within, and import it in bundle A, but
>>> in this case, ObjectFactory becomes rather useless since its trying to offer
>>> a generic facility.
>>>
>>> I've tried getting the classloader of Foo.class, but that fails in the
>>> same way with a ClassNotFoundException. I could go through the pain in B of
>>> getting the bytes that make up the class, passing them to ObjectFactory and
>>> then doing a defineClass() there, but that seems to be very complex.
>>>
>>>
>>> On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>>>
>>> What class loader are you pasing to Proxy.newProxyInstance? You should
>>> pass the one of the class you send as parameter so in your case
>>> clazz.getClassLoader.
>>>
>>> On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com>
>>> wrote:
>>>>
>>>> Sorry, I don't think I made myself particularly clear:
>>>>
>>>> I have a bundle "A" which exports a package containing a class
>>>> (ObjectFactory.class) with the method:
>>>>
>>>> public static Object getObject(Class clazz);
>>>>
>>>> This method creates a dynamic proxy object to be returned to the caller.
>>>> I have bundles B, C, and D which wish to make use of this class, and
>>>> which will call it passing an interface, for example:
>>>>
>>>> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>>>>
>>>> However, ObjectFactory throws a ClassNotFoundException because Foo.class
>>>> is not in the import list for bundle A. Is there a way of allowing this?
>>>>
>>>>
>>>> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>>>>
>>>> Jackson, Bruce wrote:
>>>>>
>>>>> Here's a question:
>>>>>
>>>>> I have a utility class in a bundle which will generate a dynamic proxy
>>>>> as a
>>>>> service to other bundles running inside Felix. Lets call this bundle
>>>>> "A".
>>>>>
>>>>> Is this possible in Felix/OSGi without having having to explicitly
>>>>> declare
>>>>> the import of the interface over which A will operate?
>>>>>
>>>>
>>>> Well, you can get access to the interface class definition by calling
>>>> Bundle.loadClass() on bundle A without importing from A, so then you
>>>> should be able to use that to create the proxy, I would imagine.
>>>>
>>>> -> richard
>>>>
>>>>> Thanks
>>>>>
>>>>> Bruce
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Alin Dreghiciu
>>> http://www.ops4j.org - New Energy for OSS Communities - Open
>>> Participation Software.
>>> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
>>> http://malaysia.jayway.net - New Energy for Projects - Great People
>>> working on Great Projects at Great Places
>>>
>>>
>>
>>
>>
>> --
>> Alin Dreghiciu
>> http://www.ops4j.org - New Energy for OSS Communities - Open
>> Participation Software.
>> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
>> http://malaysia.jayway.net - New Energy for Projects - Great People
>> working on Great Projects at Great Places
>>
>



-- 
Alin Dreghiciu
http://www.ops4j.org - New Energy for OSS Communities - Open
Participation Software.
http://www.qi4j.org - New Energy for Java - Domain Driven Development.
http://malaysia.jayway.net - New Energy for Projects - Great People
working on Great Projects at Great Places

Re: Classloading across bundles

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Interesting point...

I've done a bit more investigation around this, and actually, both clazz and ObjectManagement do appear to be accessible at the point that:

 obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz, ObjectManagement.class}, new Invoker(clazz, id, tableName));

...is called. I actually get a proxy object returned. However, its when I call a method on the object (declared in clazz) that I get the ClassNotFound exception.

I guess this could still be because the class loading doesn't really take place until methods are invoked, but its strange all the same.


On 01/08/2008 16:51, "Karl Pauls" <ka...@gmail.com> wrote:

my guess would be it's the objectmanagment class that can not be found
by the classloader of the Foo class :-)

regards,

Karl

Am 01.08.2008 um 17:31 schrieb "Jackson, Bruce" <br...@qualcomm.com>:

> Yes, the code in ObjectFactory is basically:
>
> public static Object getObject(Class clazz) {
>
>    ...
>    obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]
> {clazz, ObjectManagement.class}, new Invoker(clazz, id, tableName));
>    ...
>    return obj;
> }
>
> That's throws a ClassNotFoundException, I assume, because clazz
> (declared in B and not imported explicitly in A) is not loadable
> from with A.
>
> On 01/08/2008 16:25, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>
> Do you use Proxy.newProxyInstance?
> The first param of this method is a class loader. So, what is the
> value you use for that param? In my view you should use the
> clazz.getClassLoader that is equal with the class loader that loaded
> Foo.
> And it should not matter that you export or not the the package that
> contains Foo.
>
> On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com>
> wrote:
>> I'm not passing any classloader with my class, just the object
>> Foo.class.
>>
>> The issue is that bundle B (which is the caller to ObjectFactory
>> declared in A) does not export Foo.class, and thus the class loader
>> in A can't see it.
>> Now that's well, and good for most cases since I can always export
>> the package that Foo.class is contained within, and import it in
>> bundle A, but in this case, ObjectFactory becomes rather useless
>> since its trying to offer a generic facility.
>>
>> I've tried getting the classloader of Foo.class, but that fails in
>> the same way with a ClassNotFoundException. I could go through the
>> pain in B of getting the bytes that make up the class, passing them
>> to ObjectFactory and then doing a defineClass() there, but that
>> seems to be very complex.
>>
>>
>> On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>>
>> What class loader are you pasing to Proxy.newProxyInstance? You
>> should
>> pass the one of the class you send as parameter so in your case
>> clazz.getClassLoader.
>>
>> On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce
>> <br...@qualcomm.com> wrote:
>>> Sorry, I don't think I made myself particularly clear:
>>>
>>> I have a bundle "A" which exports a package containing a class
>>> (ObjectFactory.class) with the method:
>>>
>>> public static Object getObject(Class clazz);
>>>
>>> This method creates a dynamic proxy object to be returned to the
>>> caller.
>>> I have bundles B, C, and D which wish to make use of this class,
>>> and which will call it passing an interface, for example:
>>>
>>> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>>>
>>> However, ObjectFactory throws a ClassNotFoundException because
>>> Foo.class is not in the import list for bundle A. Is there a way
>>> of allowing this?
>>>
>>>
>>> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>>>
>>> Jackson, Bruce wrote:
>>>> Here's a question:
>>>>
>>>> I have a utility class in a bundle which will generate a dynamic
>>>> proxy as a
>>>> service to other bundles running inside Felix. Lets call this
>>>> bundle "A".
>>>>
>>>> Is this possible in Felix/OSGi without having having to
>>>> explicitly declare
>>>> the import of the interface over which A will operate?
>>>>
>>>
>>> Well, you can get access to the interface class definition by
>>> calling
>>> Bundle.loadClass() on bundle A without importing from A, so then you
>>> should be able to use that to create the proxy, I would imagine.
>>>
>>> -> richard
>>>
>>>> Thanks
>>>>
>>>> Bruce
>>>>
>>>>
>>>
>>>
>>
>>
>>
>> --
>> Alin Dreghiciu
>> http://www.ops4j.org - New Energy for OSS Communities - Open
>> Participation Software.
>> http://www.qi4j.org - New Energy for Java - Domain Driven
>> Development.
>> http://malaysia.jayway.net - New Energy for Projects - Great People
>> working on Great Projects at Great Places
>>
>>
>
>
>
> --
> Alin Dreghiciu
> http://www.ops4j.org - New Energy for OSS Communities - Open
> Participation Software.
> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> http://malaysia.jayway.net - New Energy for Projects - Great People
> working on Great Projects at Great Places
>


Re: Classloading across bundles

Posted by Karl Pauls <ka...@gmail.com>.
my guess would be it's the objectmanagment class that can not be found  
by the classloader of the Foo class :-)

regards,

Karl

Am 01.08.2008 um 17:31 schrieb "Jackson, Bruce" <br...@qualcomm.com>:

> Yes, the code in ObjectFactory is basically:
>
> public static Object getObject(Class clazz) {
>
>    ...
>    obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] 
> {clazz, ObjectManagement.class}, new Invoker(clazz, id, tableName));
>    ...
>    return obj;
> }
>
> That's throws a ClassNotFoundException, I assume, because clazz  
> (declared in B and not imported explicitly in A) is not loadable  
> from with A.
>
> On 01/08/2008 16:25, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>
> Do you use Proxy.newProxyInstance?
> The first param of this method is a class loader. So, what is the
> value you use for that param? In my view you should use the
> clazz.getClassLoader that is equal with the class loader that loaded
> Foo.
> And it should not matter that you export or not the the package that
> contains Foo.
>
> On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com>  
> wrote:
>> I'm not passing any classloader with my class, just the object  
>> Foo.class.
>>
>> The issue is that bundle B (which is the caller to ObjectFactory  
>> declared in A) does not export Foo.class, and thus the class loader  
>> in A can't see it.
>> Now that's well, and good for most cases since I can always export  
>> the package that Foo.class is contained within, and import it in  
>> bundle A, but in this case, ObjectFactory becomes rather useless  
>> since its trying to offer a generic facility.
>>
>> I've tried getting the classloader of Foo.class, but that fails in  
>> the same way with a ClassNotFoundException. I could go through the  
>> pain in B of getting the bytes that make up the class, passing them  
>> to ObjectFactory and then doing a defineClass() there, but that  
>> seems to be very complex.
>>
>>
>> On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>>
>> What class loader are you pasing to Proxy.newProxyInstance? You  
>> should
>> pass the one of the class you send as parameter so in your case
>> clazz.getClassLoader.
>>
>> On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce  
>> <br...@qualcomm.com> wrote:
>>> Sorry, I don't think I made myself particularly clear:
>>>
>>> I have a bundle "A" which exports a package containing a class  
>>> (ObjectFactory.class) with the method:
>>>
>>> public static Object getObject(Class clazz);
>>>
>>> This method creates a dynamic proxy object to be returned to the  
>>> caller.
>>> I have bundles B, C, and D which wish to make use of this class,  
>>> and which will call it passing an interface, for example:
>>>
>>> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>>>
>>> However, ObjectFactory throws a ClassNotFoundException because  
>>> Foo.class is not in the import list for bundle A. Is there a way  
>>> of allowing this?
>>>
>>>
>>> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>>>
>>> Jackson, Bruce wrote:
>>>> Here's a question:
>>>>
>>>> I have a utility class in a bundle which will generate a dynamic  
>>>> proxy as a
>>>> service to other bundles running inside Felix. Lets call this  
>>>> bundle "A".
>>>>
>>>> Is this possible in Felix/OSGi without having having to  
>>>> explicitly declare
>>>> the import of the interface over which A will operate?
>>>>
>>>
>>> Well, you can get access to the interface class definition by  
>>> calling
>>> Bundle.loadClass() on bundle A without importing from A, so then you
>>> should be able to use that to create the proxy, I would imagine.
>>>
>>> -> richard
>>>
>>>> Thanks
>>>>
>>>> Bruce
>>>>
>>>>
>>>
>>>
>>
>>
>>
>> --
>> Alin Dreghiciu
>> http://www.ops4j.org - New Energy for OSS Communities - Open
>> Participation Software.
>> http://www.qi4j.org - New Energy for Java - Domain Driven  
>> Development.
>> http://malaysia.jayway.net - New Energy for Projects - Great People
>> working on Great Projects at Great Places
>>
>>
>
>
>
> --
> Alin Dreghiciu
> http://www.ops4j.org - New Energy for OSS Communities - Open
> Participation Software.
> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> http://malaysia.jayway.net - New Energy for Projects - Great People
> working on Great Projects at Great Places
>

Re: Classloading across bundles

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Yes, the code in ObjectFactory is basically:

public static Object getObject(Class clazz) {

    ...
    obj= Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz, ObjectManagement.class}, new Invoker(clazz, id, tableName));
    ...
    return obj;
}

That's throws a ClassNotFoundException, I assume, because clazz (declared in B and not imported explicitly in A) is not loadable from with A.

On 01/08/2008 16:25, "Alin Dreghiciu" <ad...@gmail.com> wrote:

Do you use Proxy.newProxyInstance?
The first param of this method is a class loader. So, what is the
value you use for that param? In my view you should use the
clazz.getClassLoader that is equal with the class loader that loaded
Foo.
And it should not matter that you export or not the the package that
contains Foo.

On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com> wrote:
> I'm not passing any classloader with my class, just the object Foo.class.
>
> The issue is that bundle B (which is the caller to ObjectFactory declared in A) does not export Foo.class, and thus the class loader in A can't see it.
> Now that's well, and good for most cases since I can always export the package that Foo.class is contained within, and import it in bundle A, but in this case, ObjectFactory becomes rather useless since its trying to offer a generic facility.
>
> I've tried getting the classloader of Foo.class, but that fails in the same way with a ClassNotFoundException. I could go through the pain in B of getting the bytes that make up the class, passing them to ObjectFactory and then doing a defineClass() there, but that seems to be very complex.
>
>
> On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>
> What class loader are you pasing to Proxy.newProxyInstance? You should
> pass the one of the class you send as parameter so in your case
> clazz.getClassLoader.
>
> On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com> wrote:
>> Sorry, I don't think I made myself particularly clear:
>>
>> I have a bundle "A" which exports a package containing a class (ObjectFactory.class) with the method:
>>
>> public static Object getObject(Class clazz);
>>
>> This method creates a dynamic proxy object to be returned to the caller.
>> I have bundles B, C, and D which wish to make use of this class, and which will call it passing an interface, for example:
>>
>> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>>
>> However, ObjectFactory throws a ClassNotFoundException because Foo.class is not in the import list for bundle A. Is there a way of allowing this?
>>
>>
>> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>>
>> Jackson, Bruce wrote:
>>> Here's a question:
>>>
>>> I have a utility class in a bundle which will generate a dynamic proxy as a
>>> service to other bundles running inside Felix. Lets call this bundle "A".
>>>
>>> Is this possible in Felix/OSGi without having having to explicitly declare
>>> the import of the interface over which A will operate?
>>>
>>
>> Well, you can get access to the interface class definition by calling
>> Bundle.loadClass() on bundle A without importing from A, so then you
>> should be able to use that to create the proxy, I would imagine.
>>
>> -> richard
>>
>>> Thanks
>>>
>>> Bruce
>>>
>>>
>>
>>
>
>
>
> --
> Alin Dreghiciu
> http://www.ops4j.org - New Energy for OSS Communities - Open
> Participation Software.
> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> http://malaysia.jayway.net - New Energy for Projects - Great People
> working on Great Projects at Great Places
>
>



--
Alin Dreghiciu
http://www.ops4j.org - New Energy for OSS Communities - Open
Participation Software.
http://www.qi4j.org - New Energy for Java - Domain Driven Development.
http://malaysia.jayway.net - New Energy for Projects - Great People
working on Great Projects at Great Places


Re: Classloading across bundles

Posted by Alin Dreghiciu <ad...@gmail.com>.
Do you use Proxy.newProxyInstance?
The first param of this method is a class loader. So, what is the
value you use for that param? In my view you should use the
clazz.getClassLoader that is equal with the class loader that loaded
Foo.
And it should not matter that you export or not the the package that
contains Foo.

On Fri, Aug 1, 2008 at 5:17 PM, Jackson, Bruce <br...@qualcomm.com> wrote:
> I'm not passing any classloader with my class, just the object Foo.class.
>
> The issue is that bundle B (which is the caller to ObjectFactory declared in A) does not export Foo.class, and thus the class loader in A can't see it.
> Now that's well, and good for most cases since I can always export the package that Foo.class is contained within, and import it in bundle A, but in this case, ObjectFactory becomes rather useless since its trying to offer a generic facility.
>
> I've tried getting the classloader of Foo.class, but that fails in the same way with a ClassNotFoundException. I could go through the pain in B of getting the bytes that make up the class, passing them to ObjectFactory and then doing a defineClass() there, but that seems to be very complex.
>
>
> On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:
>
> What class loader are you pasing to Proxy.newProxyInstance? You should
> pass the one of the class you send as parameter so in your case
> clazz.getClassLoader.
>
> On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com> wrote:
>> Sorry, I don't think I made myself particularly clear:
>>
>> I have a bundle "A" which exports a package containing a class (ObjectFactory.class) with the method:
>>
>> public static Object getObject(Class clazz);
>>
>> This method creates a dynamic proxy object to be returned to the caller.
>> I have bundles B, C, and D which wish to make use of this class, and which will call it passing an interface, for example:
>>
>> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>>
>> However, ObjectFactory throws a ClassNotFoundException because Foo.class is not in the import list for bundle A. Is there a way of allowing this?
>>
>>
>> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>>
>> Jackson, Bruce wrote:
>>> Here's a question:
>>>
>>> I have a utility class in a bundle which will generate a dynamic proxy as a
>>> service to other bundles running inside Felix. Lets call this bundle "A".
>>>
>>> Is this possible in Felix/OSGi without having having to explicitly declare
>>> the import of the interface over which A will operate?
>>>
>>
>> Well, you can get access to the interface class definition by calling
>> Bundle.loadClass() on bundle A without importing from A, so then you
>> should be able to use that to create the proxy, I would imagine.
>>
>> -> richard
>>
>>> Thanks
>>>
>>> Bruce
>>>
>>>
>>
>>
>
>
>
> --
> Alin Dreghiciu
> http://www.ops4j.org - New Energy for OSS Communities - Open
> Participation Software.
> http://www.qi4j.org - New Energy for Java - Domain Driven Development.
> http://malaysia.jayway.net - New Energy for Projects - Great People
> working on Great Projects at Great Places
>
>



-- 
Alin Dreghiciu
http://www.ops4j.org - New Energy for OSS Communities - Open
Participation Software.
http://www.qi4j.org - New Energy for Java - Domain Driven Development.
http://malaysia.jayway.net - New Energy for Projects - Great People
working on Great Projects at Great Places

Re: Classloading across bundles

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
I'm not passing any classloader with my class, just the object Foo.class.

The issue is that bundle B (which is the caller to ObjectFactory declared in A) does not export Foo.class, and thus the class loader in A can't see it.
Now that's well, and good for most cases since I can always export the package that Foo.class is contained within, and import it in bundle A, but in this case, ObjectFactory becomes rather useless since its trying to offer a generic facility.

I've tried getting the classloader of Foo.class, but that fails in the same way with a ClassNotFoundException. I could go through the pain in B of getting the bytes that make up the class, passing them to ObjectFactory and then doing a defineClass() there, but that seems to be very complex.


On 01/08/2008 16:09, "Alin Dreghiciu" <ad...@gmail.com> wrote:

What class loader are you pasing to Proxy.newProxyInstance? You should
pass the one of the class you send as parameter so in your case
clazz.getClassLoader.

On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com> wrote:
> Sorry, I don't think I made myself particularly clear:
>
> I have a bundle "A" which exports a package containing a class (ObjectFactory.class) with the method:
>
> public static Object getObject(Class clazz);
>
> This method creates a dynamic proxy object to be returned to the caller.
> I have bundles B, C, and D which wish to make use of this class, and which will call it passing an interface, for example:
>
> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>
> However, ObjectFactory throws a ClassNotFoundException because Foo.class is not in the import list for bundle A. Is there a way of allowing this?
>
>
> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>
> Jackson, Bruce wrote:
>> Here's a question:
>>
>> I have a utility class in a bundle which will generate a dynamic proxy as a
>> service to other bundles running inside Felix. Lets call this bundle "A".
>>
>> Is this possible in Felix/OSGi without having having to explicitly declare
>> the import of the interface over which A will operate?
>>
>
> Well, you can get access to the interface class definition by calling
> Bundle.loadClass() on bundle A without importing from A, so then you
> should be able to use that to create the proxy, I would imagine.
>
> -> richard
>
>> Thanks
>>
>> Bruce
>>
>>
>
>



--
Alin Dreghiciu
http://www.ops4j.org - New Energy for OSS Communities - Open
Participation Software.
http://www.qi4j.org - New Energy for Java - Domain Driven Development.
http://malaysia.jayway.net - New Energy for Projects - Great People
working on Great Projects at Great Places


Re: Classloading across bundles

Posted by Alin Dreghiciu <ad...@gmail.com>.
What class loader are you pasing to Proxy.newProxyInstance? You should
pass the one of the class you send as parameter so in your case
clazz.getClassLoader.

On Fri, Aug 1, 2008 at 4:57 PM, Jackson, Bruce <br...@qualcomm.com> wrote:
> Sorry, I don't think I made myself particularly clear:
>
> I have a bundle "A" which exports a package containing a class (ObjectFactory.class) with the method:
>
> public static Object getObject(Class clazz);
>
> This method creates a dynamic proxy object to be returned to the caller.
> I have bundles B, C, and D which wish to make use of this class, and which will call it passing an interface, for example:
>
> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>
> However, ObjectFactory throws a ClassNotFoundException because Foo.class is not in the import list for bundle A. Is there a way of allowing this?
>
>
> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>
> Jackson, Bruce wrote:
>> Here's a question:
>>
>> I have a utility class in a bundle which will generate a dynamic proxy as a
>> service to other bundles running inside Felix. Lets call this bundle "A".
>>
>> Is this possible in Felix/OSGi without having having to explicitly declare
>> the import of the interface over which A will operate?
>>
>
> Well, you can get access to the interface class definition by calling
> Bundle.loadClass() on bundle A without importing from A, so then you
> should be able to use that to create the proxy, I would imagine.
>
> -> richard
>
>> Thanks
>>
>> Bruce
>>
>>
>
>



-- 
Alin Dreghiciu
http://www.ops4j.org - New Energy for OSS Communities - Open
Participation Software.
http://www.qi4j.org - New Energy for Java - Domain Driven Development.
http://malaysia.jayway.net - New Energy for Projects - Great People
working on Great Projects at Great Places

Re: Classloading across bundles

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Jackson, Bruce wrote:
> Sorry, I don't think I made myself particularly clear:
>
> I have a bundle "A" which exports a package containing a class (ObjectFactory.class) with the method:
>
> public static Object getObject(Class clazz);
>
> This method creates a dynamic proxy object to be returned to the caller.
> I have bundles B, C, and D which wish to make use of this class, and which will call it passing an interface, for example:
>
> Foo foo = (Foo) ObjectFactory.getObject(Foo.class);
>
> However, ObjectFactory throws a ClassNotFoundException because Foo.class is not in the import list for bundle A. Is there a way of allowing this?
>   

Ok, this makes more sense. I would assume that if you tried to make a 
proxy to clazz inside ObjectFactory.getObject() that it would use the 
ClassLoader of clazz, but apparently it is not. So, perhaps you want to 
tell dynamic proxy to use the class loader clazz.getClassLoader() when 
it creates the proxy.

-> richard

>
> On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:
>
> Jackson, Bruce wrote:
>   
>> Here's a question:
>>
>> I have a utility class in a bundle which will generate a dynamic proxy as a
>> service to other bundles running inside Felix. Lets call this bundle "A".
>>
>> Is this possible in Felix/OSGi without having having to explicitly declare
>> the import of the interface over which A will operate?
>>
>>     
>
> Well, you can get access to the interface class definition by calling
> Bundle.loadClass() on bundle A without importing from A, so then you
> should be able to use that to create the proxy, I would imagine.
>
> -> richard
>
>   
>> Thanks
>>
>> Bruce
>>
>>
>>     
>
>
>   

Re: Classloading across bundles

Posted by "Jackson, Bruce" <br...@qualcomm.com>.
Sorry, I don't think I made myself particularly clear:

I have a bundle "A" which exports a package containing a class (ObjectFactory.class) with the method:

public static Object getObject(Class clazz);

This method creates a dynamic proxy object to be returned to the caller.
I have bundles B, C, and D which wish to make use of this class, and which will call it passing an interface, for example:

Foo foo = (Foo) ObjectFactory.getObject(Foo.class);

However, ObjectFactory throws a ClassNotFoundException because Foo.class is not in the import list for bundle A. Is there a way of allowing this?


On 01/08/2008 15:14, "Richard S. Hall" <he...@ungoverned.org> wrote:

Jackson, Bruce wrote:
> Here's a question:
>
> I have a utility class in a bundle which will generate a dynamic proxy as a
> service to other bundles running inside Felix. Lets call this bundle "A".
>
> Is this possible in Felix/OSGi without having having to explicitly declare
> the import of the interface over which A will operate?
>

Well, you can get access to the interface class definition by calling
Bundle.loadClass() on bundle A without importing from A, so then you
should be able to use that to create the proxy, I would imagine.

-> richard

> Thanks
>
> Bruce
>
>


Re: Classloading across bundles

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Jackson, Bruce wrote:
> Here's a question:
>
> I have a utility class in a bundle which will generate a dynamic proxy as a
> service to other bundles running inside Felix. Lets call this bundle "A".
>
> Is this possible in Felix/OSGi without having having to explicitly declare
> the import of the interface over which A will operate?
>   

Well, you can get access to the interface class definition by calling 
Bundle.loadClass() on bundle A without importing from A, so then you 
should be able to use that to create the proxy, I would imagine.

-> richard

> Thanks
>
> Bruce
>
>