Another (somewhat similar to Carsten's) approach to this is the one that we've implemented in ECF's Remote Services/RSA implementation [1].

We've got a service interface: IClassResolver [2] and a ObjectInputStream subclass called ClassResolverObjectInputStream. The way that this works is that when creating a ClassResolverInputStream one specifies a filter for finding (via service registry) the IClassResolver service instance to use to resolve the class upon first deserialization. For example, a particular bundle (with version) that is to be responsible for resolving the classes (bundle.loadClass) for that ObjectInputStream [4]. Of course, other/custom implementations of IClassResolver are possible as well, but so far we have found the BundleClassResolver + ClassResolverObjectInputStream useful.

Scott

[1] http://wiki.eclipse.org/Eclipse_Communication_Framework_Project
[2] http://download.eclipse.org/rt/ecf/latest/javadoc/org/eclipse/ecf/core/util/IClassResolver.html [3] http://download.eclipse.org/rt/ecf/latest/javadoc/org/eclipse/ecf/core/util/ClassResolverObjectInputStream.html [4] http://download.eclipse.org/rt/ecf/latest/javadoc/org/eclipse/ecf/core/util/BundleClassResolver.html

On 10/26/2016 9:03 AM, Carsten Ziegeler wrote:
Christopher Brown wrote
Hello,

I need to define an API for an OSGi service capable of persisting arbitrary
Serializable objects as byte arrays (to disk, or over the network), and
then capable of deserializing the object via the API.  The objects to be
persisted will almost always be defined by another bundle, so the bundle
actually performing the serialization is almost always going to be unable
to access the classloader that originally provided the definition of the
serialized class (and any non-primitive attributes of that class).

Any ideas upon how to use java.io.ObjectInputStream such that its
.readObject() method can be forced to use an appropriate classloader?  I
can't see how to override its default behavior.

As for the API I need to implement (my service), it would be along the
lines of:

void service.store(String id, Object value);

<T> T service.fetch(String id, Class<T> implementationType)

...where implementationType would need to be equivalent to value.getClass()
(and not a superclass or implemented interface).  The "fetch" method would
need the "implementationType" parameter to access the CURRENT version of
the classloader (I can't store the classloader in the "store" method, first
off because I can't serialize arbitrary classloaders -- via
value.getClass().getClassloader() -- and also because the classloader might
be the wrong version, if "value" was defined by a bundle that has since
been reloaded).

Even if I replaced the "implementationType" parameter with a classloader
reference (assuming the caller of the code knew which classloader to use),
I still don't know how to override ObjectInputStream's default classloading
behavior.

Any ideas ?

You can create a subclass of ObjectInputStream and overwrite the
resolveClass method to solve the first project.

Some time ago we wrote some code, that was using a dynamic class loader
in such a subclass that simply used Package Admin to find the bundle
providing the class and then using the corresponding class loader. Of
course this requires that the classes you want to load are publicly
exported.

I'm not saying this is the best solution, but it did the trick for us.

Regards

  Carsten



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to