Serialization object construction doesn't work on JDK9 anymore
Closed this issue · 14 comments
There was an incompatible change introduced in method
sun.reflect.ReflectionFactory.newConstructorForSerialization()
in recent JDK9 b142 build.
I noticed that indeed UnsafeFactoryInstantiator
and Objenesis in general are working for standard instantiation. However, serialization isn't working anymore since ObjectStreamClassInstantiator
isn't working anymore. Let's fix that.
@henri-tremblay have you tested SunReflectionFactorySerializationInstantiator with JDK9? I was under the impression that calling setAccessible(true) fails on Java 9. See redis/lettuce@a3c36bc .
I did. And it was working. You have a different experience? Do you have a test case?
@mp911de could I trouble you for a bit more information about the commit I referenced above?
@johnou sure (mail, gitter, Twitter, …). setAccessible(true)
fails for encapsulated elements. That's the Java 8 code path. A different path
MethodHandles.lookup().findSpecial(method.getDeclaringClass(), method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()), method.getDeclaringClass());
works for Java 9 (but not Java 8 and earlier). It's however possible this might change in future Java 9 versions because "the team is fixing loopholes until the Java 9 release" (statement from an Oracle PM I met recently).
@mp911de that's perfect, just wanted to give @henri-tremblay a heads up.
Shoot! The code from above works inside of unnamed modules but not if you create a real Java 9 module and import the library that's going to invoke a default method on an interface. I found an ugly hack via a derived class. It boils down back to where we started: there's no official way to deal with Methodhandles of encapsulated components.
What do you mean by "encapsulated components"? And then it's getting annoying to test... I fell like I should just use the UnsafeInstantiator and it will be then end of it.
I'm still new to the Java 9 terminology so sorry if I don't use the right terms, still learning. I mean by that a Java 9 module with a module descriptor.
Thanks... I'm not that good with the terminology either.
So can you please confirm the current state:
1- I'm in module A which is importing module B
2- I want to create an instance of a class in module B
3- setAccessible fails
Is that it?
setAccessible
fails if the source module does not export
/opens
the package to the framework library.
setAccessible(true)
on a module's member fails when called in a framework if:
module com.my.module {
}
setAccessible(true)
on a module's member works when called in a framework if:
module com.my.module {
opens com.my.package to org.framework.module;
// or
//exports com.my.package to org.framework.module;
}
I received, however, a response to private MethodHandle
lookup yesterday, see http://mail.openjdk.java.net/pipermail/core-libs-dev/2017-March/046567.html
Oh dear Lord... First time I see "open". So, again, to make sure I get it. Let's say I have:
com.mycompany
module. It importsorg.springframework
org.springframework
module that is calling Objenesis to create a proxy. It importsorg.objenesis
org.objenesis
module
And then org.springframework
tries to create a proxy using org.objenesis
to create an instance of a class from com.mycompany
.
This will fail unless com.mycompany
is defined like this:
module com.my.module {
opens com.mycompany to org.objenesis;
}
Is that right?
I can confirm that's what you need to do for plain old jars. I'm not sure whether that's still the case when each module comes with a module descriptor and declares its dependencies. I attached a screenshot that shows a Maven and a module-info.java
to make a plain old jar working with a Java 9 module. /cc @nicolaiparlog