2

I'm updating our large old java desktop application from Java 11 to java 17. I've updated all the jars to the latest versions. jmock-2.12.0, cglib-3.3.0, asm-9.4. Working with JUnit 4 tests. A LOT of our JUnit tests are failing with a:

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 @5ce81285

Full stack trace:

java.lang.ExceptionInInitializerError
    at org.jmock.lib.legacy.ClassImposteriser.proxyClass(ClassImposteriser.java:100)
    at org.jmock.lib.legacy.ClassImposteriser.imposterise(ClassImposteriser.java:69)
    at org.jmock.Mockery.mock(Mockery.java:167)
    at com.metrixsoftware.servicebroker.MetrixTestCase.mock(MetrixTestCase.java:95)
    at com.metrixsoftware.api.mis.Test_DiecutterToolEdit.setupMetrixMISManager(Test_DiecutterToolEdit.java:125)
    at com.metrixsoftware.api.mis.Test_DiecutterToolEdit.setup(Test_DiecutterToolEdit.java:59)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:54)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
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 @5ce81285
    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)
    ... 38 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 @5ce81285
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    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:569)
    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)
    ... 50 more

Is there any way to get our calls to Mockery.mock(class,name) to work?

CasaDelGato
  • 603
  • 7
  • 17
  • Looking at the stack trace the issue is `cglib` which seems to be used by jmock? The [cglib repo](https://github.com/cglib/cglib) also has this note: `IMPORTANT NOTE: cglib is unmaintained and does not work well (or possibly at all?) in newer JDKs, particularly JDK17+`. Though, it seems like jmock can also use ByteBuddy (I think). So, you might be able to solve this be switching to ByteBuddy from cglib. – Jorn Vernee Dec 08 '22 at 22:02
  • I had found a few comments that jmock(it,or other variation) could use ByteBuddy. I don't see HOW Jmock can use it, as it references cglib classes directly. I also was a bit confused, as I was searching on Maven Central for "ByteBuddy" - and finally figured out I needed to search for "Byte-Buddy". A quick test shows that JMock is definitely using cglib classes, and not ByteBuddy ones. – CasaDelGato Dec 08 '22 at 22:17
  • 2
    Jmock seems to support different 'imposterisers'. There's also one for ByteBuddey: https://github.com/jmock-developers/jmock-library/blob/master/jmock-imposters/src/main/java/org/jmock/imposters/ByteBuddyClassImposteriser.java It seems from your stack trace that the legacy cglib-based imposteriser is being used. It also seems that the imposteriser can be set through [`Mockery.setImposteriser`](https://github.com/jmock-developers/jmock-library/blob/307f6c213ce21054c55d49311f01fb22dfc65fd2/jmock/src/main/java/org/jmock/Mockery.java#L86). So I think that's what you'll have to do. – Jorn Vernee Dec 08 '22 at 22:27
  • 3
    Looking good. After some digging around, I added "jmock-imposters-2.12.0.jar" and "byte-buddy-1.12.19.jar". Deleted cglib. Hmm, probably should delete asm as well. Also changed calls to setImposteriser() to setImposteriser(ByteBuddyClassImposteriser.INSTANCE); Running a test now. – CasaDelGato Dec 08 '22 at 23:23

1 Answers1

2

Thanks to Jorn Vernee for pointing me in the correct direction. The fix was to: Delete the cglib jar and asm jar files. Add "jmock-imposters-2.12.0.jar" and "byte-buddy-1.12.19.jar". Now JMock is working.

CasaDelGato
  • 603
  • 7
  • 17