Guice: Java 9 (JDK-9) support for guice

Created on 14 Mar 2017  路  51Comments  路  Source: google/guice

I am evaluating my projects with a pre-release Java 9 SDK. It's using recent guice that fails to inject the dependencies. Guice is trying to alter some classes in java.base module via setAccessible(...) Reflection call. Many other DI frameworks suffer from the same issue.

Are you currently working on Java 9 support for guice?

I used Java(TM) SE Runtime Environment (build 9-ea+159) and guice 1.4.1. Build target is Java 1.8.

Here is the stack trace that occured when DI-ing:

Exception in thread "Thread-0" java.lang.ExceptionInInitializerError
      at com.google.inject.internal.cglib.reflect.$FastClass$Generator.getProtectionDomain(FastClass.java:73)
      at com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:206)
      at com.google.inject.internal.cglib.reflect.$FastClass$Generator.create(FastClass.java:65)
      at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:252)
      at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:203)
      at com.google.inject.internal.ProviderMethod.create(ProviderMethod.java:69)
      at com.google.inject.internal.ProviderMethodsModule.createProviderMethod(ProviderMethodsModule.java:275)
      at com.google.inject.internal.ProviderMethodsModule.getProviderMethods(ProviderMethodsModule.java:144)
      at com.google.inject.internal.ProviderMethodsModule.configure(ProviderMethodsModule.java:123)
      at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:340)
      at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:349)
      at com.google.inject.spi.Elements.getElements(Elements.java:110)
      at com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:138)
      at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:104)
      at com.google.inject.Guice.createInjector(Guice.java:99)
      at de.client.main.Factory.createInjector(Factory.java:248)
      at de.client.main.Main$1$1.run(Main.java:76)
      at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @a42cff
      at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:335)
      at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:278)
      at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:196)
      at java.base/java.lang.reflect.Method.setAccessible(Method.java:190)
      at com.google.inject.internal.cglib.core.$ReflectUtils$1.run(ReflectUtils.java:52)
      at java.base/java.security.AccessController.doPrivileged(Native Method)
      at com.google.inject.internal.cglib.core.$ReflectUtils.<clinit>(ReflectUtils.java:42)
      ... 21 more

I can surpass that issue using the VM args --add-opens java.base/java.lang=ALL-UNNAMED

Most helpful comment

Java 9 was released a few weeks ago, it's high time to update Guice.

All 51 comments

@felixblaschke This is particularly the fault of cglib. Google "Java 9 cglib" to find relevant discussions.

@brettwooldridge are you referring to this issue? Linking to the page(s) you think are relevant is much more helpful than suggesting a Google search.

I actually wasn't referring to any one specific page. But as long as you're linking to one, I'll throw this abridged version of War and Peace into the mix.

cglib 3.2.5 seems to fix this issue. But Guice seems to repackage cglib. Therefore it seems I am not able to just include cglib 3.2.5?

But I built my own version of guice using cglib 3.2.5 and now I can launch my application with Java 9-ea+162. You should consider creating a new version of Guice with cglib 3.2.5.

yes. please release new version of guice

I'm also suffering from this problem. Releasing a new version or unbundling cglib would be nice.

The first RC for Java 9 has been published:

http://mail.openjdk.java.net/pipermail/jdk9-dev/2017-August/005940.html

So, it seems like a good time to fix this (bumping the cglib version seems like a simple fix too).

The java.lang package is open for so-call deep reflection by default so this allows existing hacks to continue to work for a bit longer. In the future then this will cause so Guice and/or cglib should look at the new Lookup.defineClass, it's the support way for libraries to inject classes.

Java 9 was released a few weeks ago, it's high time to update Guice.

What is the status of this issue? Is someone from contributors aware of this?

@DigitalSmile The whole project seems to be abandoned. Despite almost everyone uses Spring, previously I at least knew that there is a pure DI framework. And now I know of no alternatives to Spring :(

FYI: I have a branch in which I made everything work with JDK 9 - by unbundling and upgrading the dependencies. I'm using this in production on JDK9 for over a month now without a problem. The branch has the deployment settings changed to work with my local Artefactory, so if you want to use this you have to adjust the settings.

Guice is definitely not abandoned! But it's currently maintained by volunteers, and pulling everything together for a new Open Source release just hasn't been prioritized. This will get fixed, but I can't offer any sort of ETA at the moment :(

@dimo414 thanks for the insight and heads up. I can understand, it is an Open Source code and is supported by community, still it is stated very clearly, that Google has a "patronage" over this project... For months and months there are no activities (or at least all other community cannot see this).
Can we have just plans or milestones and/or some news uncovered? Because I can agree with @stIncMale - it's just look like abandoned project...

Thanks for all your effort guys! The lib is awesome.

FYI we're trying to get the OS build moving again. Stay posted!

@dimo414 are you going to fully support Jigsaw or it's just a fix for running with JDK9?

@DigitalSmile I'm not in a position to commit to supporting anything :) but we certainly want Guice to work wherever possible, and once the OS build is fixed it will be easier to address these issues.

We get a different exception when running Guice 4.1.0 with Java 9: error.log

This IllegalArgumentException is caused by the outdated ASM version Guice is using. Currently that is 5.0.3 here.

The line in the ASM source that causes the problem is that one here which explicitly makes Java versions greater than 8 fail. In ASM version 6.0 that line is definitely compatible with Java 9.

ASM 6.0 brings full support for Java 9 class files. Read the release announcement here:

The ASM 6.0 version has been released, providing full support for Java 9 class files.

@dimo414 Please update to ASM 6.0 (by replacing the jar).

@rototor You may want to upgrade to ASM 6.0 in your branch you mentioned above.

@dimo414 there are at least 3 forks I've seen that fixes it to the point where guice compiles and runs on jdk9.
That would be a good start since this is a matter of few lines of code.

Although there are tools like https://jitpack.io/ that allows you to basically build these forks and use them as maven dependency, I believe there are companies that are not exactly fine with that.
So simply fixing it to the point where it compiles and works and publishing it to maven repo with minor version increased could convince people that at least project is alive (unless they clone the git repo and check there's almost no activity on master during last few months).
Can we have some ETA?

@sameb @lukesandberg can you please take a look at the referenced PRs :cat: ? It is in fact a blocker now and soon a whole year passed since opening this issue.
Otherwise i guess i need to fork and build own versions with the patches applied so it becomes useful again. :disappointed:

I have to agree this is a royal nuisance in the buttocks. Guice + JDK9 is not really usable for us due to this issue and JDK9 has been in GA for almost 4 months now. It almost looks as if this project is orphaned.

I'd have to agree - it looks as if the public version of Guice has been left to rot. :crying_cat_face:

We're working right now to get our changes since e7bef34ef6379735e2a58df1b23f351bb7e30e44 merged in. Some of those changes get us closer to Java 9 support, and fix some of the issues in the PRs. After that, let's see what we have left to do.

aopalliance:aopalliance and javax.inject:javax.inject seem to be rather dead, too. :slightly_frowning_face:

d95c8c0cdd029a8cfda781bf48976255e059d45a updated cglib for java 9 and the following commit also addressed Java 9 issues. Do you want to try those out?

I see there's something going on on master. Can we expect the release soon?

@ronshapiro I'm able to run with Java 9 within my IDE, but not at runtime - guice still doesn't have an Automatic-Module-Name or module-info.java class yet.

@ronshapiro The current snapshot works fine for what we tested. Getting proper and finally usefull Exception messages, traces and such... i think its on a good way :smile_cat:

@kashike thanks for the reminder of those - added in #1155.

What exactly is left? I stronly think its solid enough for a release, any minor additional java9 related changes can go into a fixup point relese. Guice with java9 is really unusable and its just getting worse and wore the more time passes.
Whatever is left, it seems good enough to get a release now and a possible fixup later.

I have to agree with @anthraxx.

@ronshapiro / @netdpb : What is missing? Is there anything we could help you with? Additional testing?

With this update, will guice be compatible with jdk10 too? It is waiting behind the corner.

To support Java 10 guice has to upgrade to ASM 6.1 when it is released. Right now it is in beta2: https://gitlab.ow2.org/asm/asm/tags

We're working on the 4.2 release, hopefully for this week.

guice 4.2 is released w/ java9 support.

Thanks a lot for the work involved and taking care of this.
Guice is really a pretty amazing DI framework and I'm happy to see this finaly happened. Please keep giving it a tiny portion of love, it really deserves it :tada:

Thanks a lot for the new release. Missing bindings are now beautifully reported in the logs.

For the record though, we are still getting illegal access warnings:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/Users/bartek/.m2/repository/com/google/inject/guice/4.2.0/guice-4.2.0.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

It use to useful to test Guice with --illegal-access=deny to catch any issues that might arise when access illegal access to classes or members of classes in the JDK modules is denied. For injection then maybe Guice could loook at using Lookup.defineClass itself rather than relying on its copy of cglib to hack into protected members of java.lang.ClassLoader.

Referenced this issue in guice package for Ubuntu 18.04: https://bugs.launchpad.net/guice/+bug/1754602

ASM 6.1.1 has been released, needed for Java 10 support.
@sameb what's the plan here? Will you upgrade asm and release release 4.2.1?

ASM 6.2 released with better JDK 10 support and even with JDK 11 support already!
http://asm.ow2.io/versions.html
https://gitlab.ow2.org/asm/asm/tags
https://gitlab.ow2.org/asm/asm/issues/317830

asm 6.2.1 released.

This looks like it has made a come back in JRE 11?

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to module com.google.guice
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.Method.checkCanSetAccessible(Method.java:198)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:192)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$ReflectUtils$1.run(ReflectUtils.java:61)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$ReflectUtils.(ReflectUtils.java:52)
at com.google.[email protected]/com.google.inject.internal.cglib.reflect.$FastClassEmitter.(FastClassEmitter.java:67)
at com.google.[email protected]/com.google.inject.internal.cglib.reflect.$FastClass$Generator.generateClass(FastClass.java:77)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$AbstractClassGenerator.generate(AbstractClassGenerator.java:329)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
at com.google.[email protected]/com.google.inject.internal.cglib.core.internal.$LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at com.google.[email protected]/com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:61)
at com.google.[email protected]/com.google.inject.internal.cglib.core.internal.$LoadingCache.get(LoadingCache.java:34)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
at com.google.[email protected]/com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at com.google.[email protected]/com.google.inject.internal.cglib.reflect.$FastClass$Generator.create(FastClass.java:65)
at com.google.[email protected]/com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:258)
at com.google.[email protected]/com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:207)
at com.google.[email protected]/com.google.inject.internal.ProviderMethod.create(ProviderMethod.java:69)
at com.google.[email protected]/com.google.inject.internal.ProviderMethodsModule.createProviderMethod(ProviderMethodsModule.java:272)
at com.google.[email protected]/com.google.inject.internal.ProviderMethodsModule.getProviderMethods(ProviderMethodsModule.java:116)
at com.google.[email protected]/com.google.inject.internal.ProviderMethodsModule.configure(ProviderMethodsModule.java:100)
at com.google.[email protected]/com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:344)
at com.google.[email protected]/com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:353)
at com.google.[email protected]/com.google.inject.PrivateModule.install(PrivateModule.java:171)
at com.jwebmp.guicedpersistence/com.jwebmp.guicedpersistence.injectors.JpaPersistPrivateModule.configure(JpaPersistPrivateModule.java:50)
at com.google.[email protected]/com.google.inject.PrivateModule.configure(PrivateModule.java:101)
at com.google.[email protected]/com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:344)
at com.google.[email protected]/com.google.inject.AbstractModule.install(AbstractModule.java:103)
at com.jwebmp.guicedpersistence/com.jwebmp.guicedpersistence.db.AbstractDatabaseProviderModule.configure(AbstractDatabaseProviderModule.java:109)
at com.google.[email protected]/com.google.inject.AbstractModule.configure(AbstractModule.java:61)
at com.google.[email protected]/com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:344)
at com.google.[email protected]/com.google.inject.spi.Elements.getElements(Elements.java:103)
at com.google.[email protected]/com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:137)
at com.google.[email protected]/com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:103)
... 6 more

  • [SEVERE]

The InaccessibleObjectException in GerMarc's comment is because Guice is in a named module and it trying to hack the protected ClassLoader.defineClass method to call it from the wrong context. It can be worked around, on a temporary basis, with --add-opens java.base/java.lang=com.google.guice of course but the right solution is to get Guice fixed to use Lookup.defineClass. The reason the behavior is different when Guice is deployed on the class path is because the JDK (in JDK 9, 10 and 11) opens all the packages that existed in JDK 8 to code on the class path (not all modules) for so-called illegal access. This keeps most existing hacks working for a few releases to give the maintainers of libraries time to replace them.

Naw this was from a push up from JRE10, so it was working fine in JPMS,

I think ALL-MODULES got removed because as you pointed out exposing directly to the google guice package does get around it but using ALL-MODULES and this still comes up... Doing the module path exclusion tho makes a lot more errors later on
I've also noticed all AOP Guice in JRE11 is completely non-functional where in JRE 10 it was perfect ;)

I think there is a significant change between 10 and 11 that is breaking the injection library with regards to the exposures...

There are no changes in this area in JDK 11, the set of packages that are opened for illegal access to code on the class path is the same as JDK 9 and JDK 10. This doesn't help Guice in the example because it is deployed as a named module, not the class path (unnamed module). The right thing is course to fix Guice to use Lookup.defineClass.

Hmmm, It doesn't make sense then.
Running the exact same app in JRE 10 with named modules is 100% without any command line parameters or exclusions, simply switching from 10 to JRE 11 causes the issue. Adding the above mentioned ALL-MODULES does not work at all, in fact no difference is made in execution at all.

Setting it to --add-opens java.base/java.lang=com.google.guice,javassist does work with it specified explicitely, (Hence ALL-MODULES removed theory). But what you're saying doesn't make sense with what is happening?

Adding in the program parameter -Dcom.google.inject.internal.cglib.$experimental_asm7=true does assist somewhat but no AOP is available.

InaccessibleObjectException is because Guice is in a named module, you'll see exactly the same exception with JDK 9, 10 and 11. If Guice is on the class path then the hack will work although you should see an "Illegal reflective access" warning to point out that it will break once the java.base module is fully encapsulated.

Thanks Alan, indeed it was cglib in guice causing,

I can run with the opens exposed, and the parameter configred.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

laurentmartelli picture laurentmartelli  路  11Comments

riuvshin picture riuvshin  路  14Comments

nathanmerrill picture nathanmerrill  路  5Comments

gissuebot picture gissuebot  路  17Comments

dxiao picture dxiao  路  4Comments