-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Closed
Description
When tying to mock a class, where some transitive dependencies from the <clinit>
are missing, Mockito swallows the root cause NoClassDefFoundError
, but instead is reporting a JVM internal error
java.lang.InternalError: class redefinition failed: invalid class
, because the failing class is still tried to retransform
.
Mockito reports the following exception:
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class org.mockitousage.bugs.creation.MockClassWithMissingStaticDepTest$ClassWithErrorInCinit.
Most likely it is a private class that is not visible by Mockito
You are seeing this disclaimer because Mockito is configured to create inlined mocks.
You can learn about inline mocks and their limitations under item #39 of the Mockito class javadoc.
at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.prettifyFailure(InlineDelegateByteBuddyMockMaker.java:451)
at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createMockType(InlineDelegateByteBuddyMockMaker.java:416)
at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.doCreateMock(InlineDelegateByteBuddyMockMaker.java:367)
at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createMock(InlineDelegateByteBuddyMockMaker.java:346)
at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMock(InlineByteBuddyMockMaker.java:56)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:99)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:84)
at org.mockito.Mockito.mock(Mockito.java:2162)
at org.mockito.Mockito.mock(Mockito.java:2077)
at org.mockitousage.bugs.creation.MockClassWithMissingStaticDepTest.shouldNotSwallowCinitErrorsOfClassToMock(MockClassWithMissingStaticDepTest.java:21)
Caused by: java.lang.IllegalArgumentException: Could not create type
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:170)
at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:75)
at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createMockType(InlineDelegateByteBuddyMockMaker.java:408)
... 47 more
Caused by: java.lang.InternalError: class redefinition failed: invalid class
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:225)
at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.triggerRetransformation(InlineBytecodeGenerator.java:285)
at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.mockClass(InlineBytecodeGenerator.java:218)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.lambda$mockClass$0(TypeCachingBytecodeGenerator.java:78)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
... 52 more
Test to reporduce the issue:
public class MockClassWithMissingStaticDepTest {
@Test
public void shouldNotSwallowCinitErrorsOfClassToMock() {
try {
@SuppressWarnings("unused")
var unused = Mockito.mock(ClassWithErrorInClinit.class);
fail();
} catch (MockitoException e) {
e.printStackTrace();
var cause = e.getCause();
assertThat(cause).isInstanceOf(MockitoException.class);
assertThat(cause.getMessage()).isEqualTo("Cannot instrument class org.mockitousage.bugs.creation.MockClassWithMissingStaticDepTest$ClassWithErrorInCinit because it or one of its supertypes could not be initialized");
var cause2 = cause.getCause();
assertThat(cause2).isInstanceOf(NoClassDefFoundError.class);
assertThat(cause2.getMessage()).isEqualTo("Simulate missing transitive dependency used in <clinit>.");
}
}
private static class ClassWithErrorInClinit {
static {
//noinspection ConstantValue
if (true) {
throw new NoClassDefFoundError("Simulate missing transitive dependency used in <clinit>.");
}
}
}
}
Root-Cause
The method org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.assureInitialization()
only handles ExceptionInInitializerError
and swallows everything else.
Expected behavior
Mockito shall report the first NoClassDefFoundError
instead of swallowing it.
Affected version: 5.14.2
Affected JVM: 21
I will open a PR to fix the issue.
Metadata
Metadata
Assignees
Labels
No labels