-
Notifications
You must be signed in to change notification settings - Fork 60
Open
Description
Using Mockito 4.6.1 and Scala 2.13.10:
class Foo[A] {
final def go(x: Foo[Object]): Object = "foo"
}
class Bar extends Foo[Object] {
def go(x: Foo[String]): String = "bar"
}
object Test {
def main(args: Array[String]): Unit =
org.mockito.Mockito.mock(classOf[Bar])
}
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class Bar.
Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
Java : 19
JVM vendor name : Homebrew
JVM vendor version : 19.0.2
JVM name : OpenJDK 64-Bit Server VM
JVM version : 19.0.2
JVM info : mixed mode, sharing
OS name : Mac OS X
OS version : 12.5
Underlying exception : java.lang.IllegalStateException: java.lang.IncompatibleClassChangeError: class Bar$MockitoMock$Xo3ch4tG overrides final method Foo.go(LFoo;)Ljava/lang/Object;
at Test$.main(Main.scala:11)
at Test.main(Main.scala)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
Caused by: java.lang.IllegalStateException: java.lang.IncompatibleClassChangeError: class Bar$MockitoMock$Xo3ch4tG overrides final method Foo.go(LFoo;)Ljava/lang/Object;
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$UsingUnsafeInjection.defineClass(ClassInjector.java:1045)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.injectRaw(ClassInjector.java:284)
at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:118)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:241)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6166)
at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:297)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.lambda$mockClass$0(TypeCachingBytecodeGenerator.java:47)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
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:40)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:77)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:43)
at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:42)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:53)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:96)
at org.mockito.Mockito.mock(Mockito.java:1981)
at org.mockito.Mockito.mock(Mockito.java:1896)
at Test$.main(Main.scala:11)
at Test.main(Main.scala)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
Caused by: java.lang.IncompatibleClassChangeError: class Bar$MockitoMock$Xo3ch4tG overrides final method Foo.go(LFoo;)Ljava/lang/Object;
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013)
at java.base/java.lang.ClassLoader$ByteBuddyAccessor$V1.defineClass(Unknown Source)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$UsingUnsafeInjection.defineClass(ClassInjector.java:1041)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.injectRaw(ClassInjector.java:284)
at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:118)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:241)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6166)
at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:297)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.lambda$mockClass$0(TypeCachingBytecodeGenerator.java:47)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
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:40)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:77)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:43)
at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:42)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:53)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:96)
at org.mockito.Mockito.mock(Mockito.java:1981)
at org.mockito.Mockito.mock(Mockito.java:1896)
at Test$.main(Main.scala:11)
at Test.main(Main.scala)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
Note that the equivalent with Java just doesn't compile with javac. Possibly scalac shouldn't compile it either:
public class Foo<A> {
public final Object go(Foo<Object> x) {
return "foo";
}
}
public class Bar extends Foo<Object> {
public String go(Foo<String> x) {
return "bar";
}
}
I think the problem is in ByteBuddy's MethodGraph.Compiler which is using Java rather than JVM semantics, so not considering the return type in the erasure. Also, maybe it should use the bridge flag rather than the erasure to distinguish.
(Originally reported as mockito/mockito#2929.)
Metadata
Metadata
Assignees
Labels
No labels