Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mockStatic fails with class redefinition failed: invalid class #3273

Open
scordio opened this issue Feb 17, 2024 · 5 comments
Open

mockStatic fails with class redefinition failed: invalid class #3273

scordio opened this issue Feb 17, 2024 · 5 comments

Comments

@scordio
Copy link
Contributor

scordio commented Feb 17, 2024

Mockito message in the stack trace:

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:167)
	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.triggerRetransformation(InlineBytecodeGenerator.java:281)
	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.mockClassStatic(InlineBytecodeGenerator.java:226)
	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClassStatic(TypeCachingBytecodeGenerator.java:108)
	at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createStaticMock(InlineDelegateByteBuddyMockMaker.java:592)
	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createStaticMock(InlineByteBuddyMockMaker.java:83)
	at org.mockito.internal.util.MockUtil.createStaticMock(MockUtil.java:202)
	at org.mockito.internal.MockitoCore.mockStatic(MockitoCore.java:134)
	at org.mockito.Mockito.mockStatic(Mockito.java:2328)
	at org.mockito.Mockito.mockStatic(Mockito.java:2265)
	at <line of try block in test method>

The problematic class belongs to the Thales JCPROV library which is unfortunately not available on Maven Central so I cannot compose a reproducer.

However, I can describe its characteristics:

  • Public, top level and non-final
  • With a default constructor that is private and does nothing
  • With public methods that are all static and native
  • With a static initialization block that loads a native library via System.loadLibrary

As the native library is not available during test execution (and I cannot make it available), I would guess that the failure in the static block triggers the exception above. However, I don't know how to prove it.

Is there anything I could do to properly mock such a class? Otherwise, do you see any possible improvements in Mockito for these cases?

Please, let me know in case I could grab additional details to help the analysis.

The issue happens on Mockito 5.10.0 and OpenJDK 11.0.12.

@scordio scordio changed the title mockStatic fails with Class redefinition failed mockStatic fails with Class redefinition failed: invalid class Feb 17, 2024
@scordio scordio changed the title mockStatic fails with Class redefinition failed: invalid class mockStatic fails with class redefinition failed: invalid class Feb 17, 2024
@jkim323
Copy link

jkim323 commented Feb 25, 2024

Although I am unfamiliar to the the Thales JCPROV library, I am a bit curious on this issue. I am wondering if you have tried checking if your class is missing in your class path by simply trying to use the static method before mocking it because this has happened to me once before. But based on your issue since you are work involves with native code maybe mocking the native methods is not the best route because I have heard of challenges on doing this. Have you tried exploring doing something like encapsulating it in a wrapper class or in an interface?

@scordio
Copy link
Contributor Author

scordio commented Feb 25, 2024

Yes, the library is in the classpath: if I call one of the methods without mocking, it fails in the static initialization block with a missing native library error, as expected.

Also yes, wrapping works fine as a workaround. In addition, there is another class (still part of the library) that offers similar static methods, wrapping each native call with exception throwing in case of errors, and mocking this class works as expected.

@jkim323
Copy link

jkim323 commented Feb 25, 2024

Interesting. Does the other successful class also share the same characteristics as the class you are having problems with or are there differences? I am wondering if two classes share the last bullet you mentioned in the post. Also, have you explored using PowerMock perhaps?

@scordio
Copy link
Contributor Author

scordio commented Feb 25, 2024

No, they are not the same. The successful one:

  • Is also public, top level and non-final
  • Has also default constructor that is private and does nothing
  • Has public methods that are all static but not native
  • Has no static initialization block (i.e., no load of a native library)

Imagine something like:

public class NativeClass {

  private NativeClass() {}

  public static native int method();

  static {
    System.loadLibrary("native");
  }

}

public class WrapperClass {

  private WrapperClass() {}

  public static int method() {
    int result = NativeClass.method();
    if (result != 0) throw new RuntimeException(result);
  }

}

(written without checking the original code – beware of typos 🙂 )

@jkim323
Copy link

jkim323 commented Feb 26, 2024

After reading your difference , it makes sense to why you are seeing it fail because it seems like a common known issue that Mockito is unable to mock native methods; it is currently a limitation on Mockito as of now. Perhaps you can try PowerMock as an alternative solution but I am not aware of a definitive solution.. unless we develop on this maybe creating a discussion on this topic might help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants