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

Make reflective call to Lookup lazy on first default method invocation #3448

Closed
Dragas opened this issue Jul 28, 2020 · 8 comments
Closed

Make reflective call to Lookup lazy on first default method invocation #3448

Dragas opened this issue Jul 28, 2020 · 8 comments

Comments

@Dragas
Copy link

Dragas commented Jul 28, 2020

After moving my project to fully support JPMS (JDK11), and retrofit has become unusable due to the following error:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make private java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int) accessible: module java.base does not "opens java.lang.invoke" to module retrofit2
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
	at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:189)
	at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:182)
	at retrofit2@2.9.0/retrofit2.Platform.<init>(Platform.java:59)
	at retrofit2@2.9.0/retrofit2.Platform.findPlatform(Platform.java:44)
	at retrofit2@2.9.0/retrofit2.Platform.<clinit>(Platform.java:35)
	... 11 more

It seems that retrofit deeply depends on Java's Lookup class and making its constructor visible to itself. The issue becomes apparent, when using the JPMS. A workaround for this is to add --add-opens java.base/java.lang.invoke=retrofit2 but it would be nice if there wasn't such need to expose the base module's packages myself. Perhaps add a call to Module#addOpen(String, Module) when initializing retrofit's class?

@JakeWharton
Copy link
Member

If you can move to JDK 14 or newer this reflective call is no longer required. I suspect we'll probably make it lazy rather than eager, but I don't see us adding a call to Module (unless that also was done with reflection).

@JakeWharton
Copy link
Member

#3444 was the motivation for making it lazy. This is yet another reason!

The reflection is only needed when your service interfaces have default methods (on pre-14).

@Dragas
Copy link
Author

Dragas commented Jul 29, 2020

I doubt reflectively calling Module class will solve the issue, considering open declaration in module definition is what permits reflective operations against module exposing a package. See the following for JDK11 https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/module-info.java, which does not contain an open declaration on java.lang package. Nor does JDK14 https://hg.openjdk.java.net/jdk/jdk14/file/6c954123ee8d/src/java.base/share/classes/module-info.java

@JakeWharton
Copy link
Member

I can't reflectively invoke public API? That's pretty nonsensical on the JDKs part. But since this isn't a problem with JDK 14 any more I'm inclined to make the reflective lookup on Lookup lazy on first use and if you are using default methods on pre-14 in the module system then you'll just have to live with opening up java.base until you can upgrade to 14 or newer.

@Dragas
Copy link
Author

Dragas commented Jul 29, 2020

Fair enough.

@robertvazan
Copy link

@JakeWharton You can definitely access all public APIs via reflection even with strong module encapsulation.

@JakeWharton JakeWharton changed the title Unable to access "java.base/java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int)" Make reflective call to Lookup lazy on first default method invocation Mar 21, 2022
@nienienienie
Copy link

true :)

If you can move to JDK 14 or newer this reflective call is no longer required.

I had JDK 11 and warning was there.

Then I moved to JDK 17 and it's gone.

@JakeWharton
Copy link
Member

This happened, at some point. The lookup is now lazy.

Constructor<Lookup> constructor = lookupConstructor;
if (constructor == null) {

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

No branches or pull requests

4 participants