24

I have cglib as a transitive dependency in a Maven project. Despite adding what I believe to be the correct --add-opens I can't get the library to work with Java 16.

How do I get cglib to work with Java 16? I raised this issue on the github page.

Minimal reproducible example:

Main.java

import net.sf.cglib.proxy.Enhancer; public class Main { public static void main(String[] args) { new Enhancer(); } } 

With Java 15:

javac -cp cglib-3.3.0.jar Main.java

java --add-opens java.base/java.lang=ALL-UNNAMED -cp cglib-3.3.0.jar:asm-7.1.jar:. Main

Picked up _JAVA_OPTIONS: -Duser.language=en -Duser.country=GB WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by net.sf.cglib.core.ReflectUtils$1 (file:/Users/rbain/Desktop/cglib-3.3.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 net.sf.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 

With Java 16:

javac -cp cglib-3.3.0.jar Main.java

java --add-opens java.base/java.lang=ALL-UNNAMED -cp cglib-3.3.0.jar:asm-7.1.jar:. Main

Exception in thread "main" java.lang.ExceptionInInitializerError at Main.main(Main.java:5) Caused by: net.sf.cglib.core.CodeGenerationException: 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 @11739fa6 at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:464) at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:339) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94) at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294) at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221) at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:174) at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:153) at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73) ... 1 more 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 @11739fa6 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199) at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) at net.sf.cglib.core.ReflectUtils$1.run(ReflectUtils.java:61) at java.base/java.security.AccessController.doPrivileged(AccessController.java:554) at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:52) at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:243) at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332) ... 13 more 
7
  • 1
    do you understand what Rafael said with "you can change the setting that forbids accessing internal API"? I do not, so wondering Commented Apr 6, 2021 at 20:17
  • @Eugene I wasn't certain but I thought he meant add the --add-opens. Commented Apr 6, 2021 at 20:18
  • 1
    that does not look like a "forbid" though. may be he is talking about some certain internal cglib flag? Commented Apr 6, 2021 at 20:19
  • 3
    Rafael surely meant --illegal-access=…. Prior to JDK 16, its default was --illegal-access=permit, now it’s --illegal-access=deny. You may override it and gain some time until JEP 403 gets implemented and the whole thing will break again. Commented Apr 8, 2021 at 11:06
  • 4
    The long-run solution is to get an update of cglib that doesn't use internal API points in this way, since relatively soon, the workarounds will stop working. You need to report this problem to the cglib maintainers; this is their problem to fix. Commented Jun 29, 2021 at 18:32

1 Answer 1

34
+300

Since JDK 16, the default for the --illegal-access option is deny, so “deep reflection” to JDK classes fails.

You can override the behavior by specifying --illegal-access=permit, but you have to be aware of JEP 403: Strongly Encapsulate JDK Internals which is about closing that possibility in a future version, so this option is only a temporary solution.

The permanent solution is to update cglib to a compatible version if/once it exists. The attempt to access ClassLoader.defineClass suggests that the library wants to add classes to a particular context, which can be done via MethodHandles.lookup().defineClass instead (since Java 9). So the code only has to switch to the new way of adding classes.

Sign up to request clarification or add additional context in comments.

10 Comments

fyi, took the liberty to reference this back to the GitHub issue linked in the question for future audience
From JDK17 on, setting --illegal-access=permit or warn doesn't work any longer. it is still possible to build a workaround by manually specifying "add-opens" for accessed packages in the manifest or as jvmArg (e.g. --add-opens=java.base/java.util=ALL-UNNAMED)
@FlorianKoch well, yes, ⅔ of this answer are about the expectation of this to happen. The real fix is described as well. Using --add-opens can also only be a temporary work-around and requires the user to know precisely a) the module/package to open and b) to which target module it needs to be opened.
@FlorianKoch then, there’s no way to fix the problem on your side. But there should be maintainers already working on the problem at the other side. If not, it’s time to think about long term migration…
@gerumato letting aside that this can’t be java 1.8, it’s precisely the same issue. Maybe, you mean java 18?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.