Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

com.typesafe.config.impl.SerializedConfigValue should be exported in OSGi manifest #49

Closed
slavaschmidt opened this issue Nov 16, 2012 · 11 comments

Comments

@slavaschmidt
Copy link

Now the com.typesafe.config.impl package is defined as private, which prevents akka 2.0 from working in remote scenarios with remote deployment. The reason for this is that the com.typesafe.config.impl.SerializedConfigValue class is not available for the akka.remote.MessageSerializer:

    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:622)
    at akka.util.ClassLoaderObjectInputStream.resolveClass(ClassLoaderObjectInputStream.scala:12)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1593)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
    at akka.serialization.JavaSerializer$$anonfun$1.apply(Serializer.scala:121)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
    at akka.serialization.JavaSerializer.fromBinary(Serializer.scala:121)
    at akka.serialization.Serialization.deserialize(Serialization.scala:73)
    at akka.remote.MessageSerializer$.deserialize(MessageSerializer.scala:22)
    at akka.remote.RemoteMessage.payload(RemoteTransport.scala:212)
    at akka.remote.RemoteMarshallingOps$class.receiveMessage(RemoteTransport.scala:274)
    at akka.remote.netty.NettyRemoteTransport.receiveMessage(NettyRemoteSupport.scala:46)
    at akka.remote.netty.RemoteServerHandler.messageReceived(Server.scala:182)
    at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75)
    at akka.remote.netty.RemoteServerHandler.handleUpstream(Server.scala:154)
    at org.jboss.netty.channel.StaticChannelPipeline.sendUpstream(StaticChannelPipeline.java:372)
    at org.jboss.netty.channel.StaticChannelPipeline$StaticChannelHandlerContext.sendUpstream(StaticChannelPipeline.java:534)
    at org.jboss.netty.handler.execution.ChannelUpstreamEventRunnable.doRun(ChannelUpstreamEventRunnable.java:45)
    at org.jboss.netty.handler.execution.ChannelEventRunnable.run(ChannelEventRunnable.java:69)
    at org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor$ChildExecutor.run(OrderedMemoryAwareThreadPoolExecutor.java:315)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

Thanks for looking into this!

@viktorklang
Copy link
Contributor

AFAIK this was already fixed in later versions of Typesafe Config, just exclude the Akka Typesafe Config dependency and add your own. Does that fix the issue?

@viktorklang
Copy link
Contributor

Assuming that you're on Akka 2.0.4 (which is the latest release for 2.0)

@slavaschmidt
Copy link
Author

Hi Viktor and thank you for the quick response. Yes i'm on 2.0.4. I can't exclude the dependency on Config as it is very useful and used by other components of the application as well.

For now i just changed the Manifest of the Config so that the class in question is exported as well, but i think it could be the issue for somebody else.

Thanks again

@viktorklang
Copy link
Contributor

But why does OSGi need internal implementation details to be exported? That seems buggy to me.

@havocp
Copy link
Collaborator

havocp commented Nov 16, 2012

Java serialization is just full of hacks. We use the writeReplace() mechanism to provide an internal object to be serialized rather than the original object. Normally, serialization doesn't care that the replacement object has a private class, but with OSGi the class loader actively blocks loading the private class I guess, so the Java deserializer can't load it to call readExternal().

Putting the internal class in the manifest does sound like the only solution, though I don't really understand OSGi in much detail. Hopefully there's a way to export just the one class and not the whole "impl" package.

@slavaschmidt
Copy link
Author

Basically, all classes that are needed to construct (or clone or deserialize) an object must be available for the class loader. In OSGi some class is available if it's package is exported by some bundle (with respect to the version information). If some package declared private, it is available only for the declaring bundle.

I would say that if an application relies on the serialised form of something, than this serialised form should be considered to be a part of the API.

Yes, i think there is no need to export full package. I'd export the serialised form only. For example, by moving this class from the "impl" package. This will work but it will also create another issue with cyclic package dependencies :)

@havocp
Copy link
Collaborator

havocp commented Sep 20, 2013

I'm not sure what the actual appropriate change in the typesafe config code is; I've never dealt with OSGi. I would like to keep this class "as private as possible" while still keeping OSGi working. I might need a patch or at least a description of the changes.

@mpilquist
Copy link
Contributor

What about moving SerializedConfigValue to com.typesafe.config package but change its accessibility to default (from public)?

@havocp
Copy link
Collaborator

havocp commented Jan 6, 2014

If default access would work that sounds fine, but renaming the class would break serialization back-compat, which could cause akka upgrade problems (I think? I know we've discussed it). In retrospect, a class name which appears in the serialization probably should not have had "impl" in it. Ugh.

@havocp
Copy link
Collaborator

havocp commented Jan 9, 2014

Where I currently have OsgiKeys.exportPackage := Seq("com.typesafe.config") in the build, is there any huge downside to just adding the impl package to the export list? It means OSGi users can use the impl but non-OSGi users can cheat and do that too, and in both cases we just tell them they are wrong and they get both pieces when it breaks, right?

@mpilquist
Copy link
Contributor

No huge downside - just what you already listed. The package has impl in its name so that's typically enough of a clue to users to stay away from it. This is probably the simplest solution that maintains full compatibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants