question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ReflectUtils breaks with Java 9 build 148+

See original GitHub issue

Since Java 9 build 148, it is no longer possible to do setAccessible on any public Java runtime API class (except sun.misc.Unsafe as special case). This affects ClassLoader#defineClass (protected method).

Because of this any mocking library (Mockito, EasyMock,…) that uses CGLIB breaks with ExceptionOnInitializer.

Example in Apache Solr (Mockito/Easymock):

   [junit4] ERROR   0.38s J2 | TestManagedSchemaThreadSafety.testThreadSafety <<<
   [junit4]    > Throwable #1: java.lang.ExceptionInInitializerError
   [junit4]    >        at __randomizedtesting.SeedInfo.seed([8E654E5E1F32A757:142F5A06CCAD15A1]:0)
   [junit4]    >        at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167)
   [junit4]    >        at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
   [junit4]    >        at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
   [junit4]    >        at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
   [junit4]    >        at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117)
   [junit4]    >        at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109)
   [junit4]    >        at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105)
   [junit4]    >        at org.mockito.cglib.proxy.Enhancer.<clinit>(Enhancer.java:70)
   [junit4]    >        at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:85)
   [junit4]    >        at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
   [junit4]    >        at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
   [junit4]    >        at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
   [junit4]    >        at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
   [junit4]    >        at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
   [junit4]    >        at org.mockito.Mockito.mock(Mockito.java:1243)
   [junit4]    >        at org.apache.solr.schema.TestManagedSchemaThreadSafety.createZkController(TestManagedSchemaThreadSafety.java:135)
   [junit4]    >        at org.apache.solr.schema.TestManagedSchemaThreadSafety.testThreadSafety(TestManagedSchemaThreadSafety.java:118)
   [junit4]    >        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   [junit4]    >        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   [junit4]    >        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   [junit4]    >        at java.base/java.lang.reflect.Method.invoke(Method.java:538)
   [junit4]    >        at java.base/java.lang.Thread.run(Thread.java:844)
   [junit4]    > 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 @4cbd6df7
   [junit4]    >        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:207)
   [junit4]    >        at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:192)
   [junit4]    >        at java.base/java.lang.reflect.Method.setAccessible(Method.java:186)
   [junit4]    >        at org.mockito.cglib.core.ReflectUtils$2.run(ReflectUtils.java:57)
   [junit4]    >        at java.base/java.security.AccessController.doPrivileged(Native Method)
   [junit4]    >        at org.mockito.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:47)
   [junit4]    >        ... 55 more
   [junit4]   2> 64469 INFO  (SUITE-TestManagedSchemaThreadSafety-seed#[8E654E5E1F32A757]-worker) [    ] o.a.s.c.ZkTestServer connecting to 127.0.0.1:51648 51648
   [junit4]   2> 64474 INFO  (Thread-158) [    ] o.a.s.c.ZkTestServer connecting to 127.0.0.1:51648 51648
   [junit4]   2> 64478 INFO  (SUITE-TestManagedSchemaThreadSafety-seed#[8E654E5E1F32A757]-worker) [    ] o.a.s.SolrTestCaseJ4 ###deleteCore
   [junit4]   2> NOTE: leaving temporary files on disk at: C:\Users\Uwe Schindler\Projects\lucene\trunk-lusolr1\solr\build\solr-core\test\J2\temp\solr.schema.TestManagedSchemaThreadSafety_8E654E5E1F32A757-001
   [junit4]   2> Dez. 26, 2016 8:47:14 NACHM. com.carrotsearch.randomizedtesting.ThreadLeakControl checkThreadLeaks
   [junit4]   2> WARNUNG: Will linger awaiting termination of 2 leaked thread(s).
   [junit4]   2> NOTE: test params are: codec=Lucene70, sim=RandomSimilarity(queryNorm=false): {}, locale=so-KE, timezone=Etc/GMT+4
   [junit4]   2> NOTE: Windows 10 10.0 amd64/Oracle Corporation 9-ea (64-bit)/cpus=4,threads=1,free=188820656,total=266338304
   [junit4]   2> NOTE: All tests run in this JVM: [TestRandomFaceting, TestCharFilters, BlockJoinFacetSimpleTest, SolrCmdDistributorTest, TestTolerantUpdateProcessorRandomCloud, TestManagedSchemaThreadSafety]
   [junit4] Completed [31/670 (1!)] on J2 in 0.83s, 1 test, 1 error <<< FAILURES!

I have no idea why CGLib needs to do this (instead of just subclassing ClassLoader). I have the feeling that mocking libs need to “inject” classes into existing classloaders, so the workaround is needed.

A trick to solve this might be using MethodHandles instead of Reflection using a “temporary” child class of ClassLoader (just to get a MethodHandle to the defineClass method). But this would require minimum Java 7. I may provide a PR to do this.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:29 (12 by maintainers)

github_iconTop GitHub Comments

4reactions
raphwcommented, Dec 26, 2016

It’s not that easy. Creating a new class loader causes the generated code to be loaded by another class loader. Even if the class’s package name is the same, the loaded class will exist in a different runtime package what limits the scope of classes that can be subclassed. There is no backwards-compatible way for us to resolve this.

This issue is not easy to workaround and I still hoping that this will not make the final release of Java 9, this change would break thousands of projects. For now, I suggest to wait and see as creating a new class loader every time is a very breaking change.

This is also a major performance issue as class loaders are quite expensive to create.

As for Mockito: It does no longer use cglib in more recent versions but the problem prevails for any other code generation library.

1reaction
raphwcommented, Dec 27, 2016

I stumbled upon the same problem, would have been too good to be true.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Rafael Winterhalter on Twitter: "This is why Java 9 will blow up ...
ReflectUtils breaks with Java 9 build 148 + · Issue #93 · cglib/cglib. Since Java 9 build 148, it is no longer possible...
Read more >
Failed to start java application using jdk 9 ea build 148
When I tries to run a Jigsaw app using jdk-9-ea-build-148 it fails with the following exception: java.lang.reflect.LayerInstantiationException: Package ...
Read more >
JDK 9 Release Notes - Oracle
This document describes important new changes and information for the Oracle JDK 9 release.
Read more >
Java 9 Illegal Reflective Access Warning - Baeldung
Even reflection can't break the readability and accessibility rules; otherwise, it will lead to corresponding errors or warnings. One thing to ...
Read more >
IntelliJ doesn't Understand java libraries on Java9-ea
Speaking of JDK 9, IntelliJ IDEA 2016.3 won't support builds 148 and up because they contain code that breaks things.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found