Repository: mockito/mockito
Issue: Incompatibility between the inline mocks and JaCoCo 0.8.4

# Versions

Mockito 2.27.0
JaCoCo 0.8.4

# Problem

JaCoCo 0.8.4 introduced the use of the Conditional Dynamic instruction when running with Java 11+, which triggers an exception in the [`MethodVisitor`](https://github.com/mockito/mockito/blob/v2.27.0/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java#L314) used to strip the parameters, because it's not configured for the correct ASM API version:

    Mockito cannot mock this class: class com.ekino.mockito.B.
    
    If you're not sure why you're getting this error, please report to the mailing list.
    
    
    Java               : 11
    JVM vendor name    : AdoptOpenJDK
    JVM vendor version : 11.0.3+7
    JVM name           : OpenJDK 64-Bit Server VM
    JVM version        : 11.0.3+7
    JVM info           : mixed mode
    OS name            : Mac OS X
    OS version         : 10.14.5
    
    
    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.
    
    Underlying exception : org.mockito.exceptions.base.MockitoException: Could not modify all classes [class java.lang.Object, class com.ekino.mockito.B]
    org.mockito.exceptions.base.MockitoException: 
    Mockito cannot mock this class: class com.ekino.mockito.B.
    
    If you're not sure why you're getting this error, please report to the mailing list.
    
    
    Java               : 11
    JVM vendor name    : AdoptOpenJDK
    JVM vendor version : 11.0.3+7
    JVM name           : OpenJDK 64-Bit Server VM
    JVM version        : 11.0.3+7
    JVM info           : mixed mode
    OS name            : Mac OS X
    OS version         : 10.14.5
    
    
    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.
    
    Underlying exception : org.mockito.exceptions.base.MockitoException: Could not modify all classes [class java.lang.Object, class com.ekino.mockito.B]
    	at com.ekino.mockito.ATest.should_call_b(ATest.java:10)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:628)
    	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:117)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:184)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:180)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:127)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    	at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
    	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    	at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
    	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
    	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
    	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:102)
    	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:82)
    	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:78)
    	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    	at com.sun.proxy.$Proxy5.stop(Unknown Source)
    	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
    	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
    	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
    	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    	at java.base/java.lang.Thread.run(Thread.java:834)
    Caused by: org.mockito.exceptions.base.MockitoException: Could not modify all classes [class java.lang.Object, class com.ekino.mockito.B]
    	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:152)
    	at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:365)
    	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:174)
    	at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:376)
    	... 77 more
    Caused by: java.lang.IllegalStateException: 
    Byte Buddy could not instrument all classes within the mock's type hierarchy
    
    This problem should never occur for javac-compiled classes. This problem has been observed for classes that are:
     - Compiled by older versions of scalac
     - Classes that are part of the Android distribution
    	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.triggerRetransformation(InlineBytecodeGenerator.java:177)
    	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.mockClass(InlineBytecodeGenerator.java:153)
    	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:37)
    	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:34)
    	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:152)
    	at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:365)
    	at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:174)
    	at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:376)
    	at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:32)
    	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMockType(InlineByteBuddyMockMaker.java:197)
    	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMock(InlineByteBuddyMockMaker.java:178)
    	at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
    	at org.mockito.internal.MockitoCore.mock(MockitoCore.java:62)
    	at org.mockito.Mockito.mock(Mockito.java:1907)
    	at org.mockito.Mockito.mock(Mockito.java:1816)
    	... 77 more
    Caused by: java.lang.UnsupportedOperationException: This feature requires ASM7
    	at net.bytebuddy.jar.asm.MethodVisitor.visitLdcInsn(MethodVisitor.java:542)
    	at net.bytebuddy.jar.asm.ClassReader.readCode(ClassReader.java:2181)
    	at net.bytebuddy.jar.asm.ClassReader.readMethod(ClassReader.java:1275)
    	at net.bytebuddy.jar.asm.ClassReader.accept(ClassReader.java:679)
    	at net.bytebuddy.jar.asm.ClassReader.accept(ClassReader.java:391)
    	at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:3393)
    	at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1930)
    	at net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:217)
    	at net.bytebuddy.dynamic.scaffold.inline.AbstractInliningDynamicTypeBuilder.make(AbstractInliningDynamicTypeBuilder.java:120)
    	at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3396)
    	at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.transform(InlineBytecodeGenerator.java:254)
    	at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
    	at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    	at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
    	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:174)
    	... 91 more

# Example

I've pushed an [example](https://github.com/fpavageau/mockito-jacoco-condy) demonstrating the problem.

# Fix

I believe the fix is simply to configure the visitor with the ASM 7 API version, since that _is_ the version used by Mockito.

Issue comments:
For reference, the change was introduced in JaCoCo with jacoco/jacoco#845.

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
index e160e3cb2d..34b1e89855 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
@@ -20,7 +20,6 @@
 import net.bytebuddy.implementation.Implementation;
 import net.bytebuddy.jar.asm.ClassVisitor;
 import net.bytebuddy.jar.asm.MethodVisitor;
-import net.bytebuddy.jar.asm.Opcodes;
 import net.bytebuddy.matcher.ElementMatchers;
 import net.bytebuddy.pool.TypePool;
 import net.bytebuddy.utility.OpenedClassReader;
@@ -311,7 +310,7 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
         private static class MethodParameterStrippingMethodVisitor extends MethodVisitor {
 
             public MethodParameterStrippingMethodVisitor(MethodVisitor mv) {
-                super(Opcodes.ASM5, mv);
+                super(OpenedClassReader.ASM_API, mv);
             }
 
             @Override


Test patch:
diff --git a/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java b/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java
index eebdb962d7..7d3647e6e8 100644
--- a/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java
+++ b/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java
@@ -8,7 +8,9 @@
 import net.bytebuddy.ClassFileVersion;
 import net.bytebuddy.description.modifier.Visibility;
 import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.implementation.FixedValue;
 import net.bytebuddy.implementation.StubMethod;
+import net.bytebuddy.utility.JavaConstant;
 import org.junit.Test;
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.internal.creation.MockSettingsImpl;
@@ -25,9 +27,11 @@
 import java.util.Observable;
 import java.util.Observer;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.regex.Pattern;
 
 import static net.bytebuddy.ClassFileVersion.JAVA_V8;
+import static net.bytebuddy.ClassFileVersion.JAVA_V11;
 import static net.bytebuddy.matcher.ElementMatchers.named;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
@@ -291,6 +295,25 @@ public void test_parameters_retention() throws Exception {
                 .getOnly().getParameters().getOnly().getName()).isEqualTo("bar");
     }
 
+    @Test
+    public void test_constant_dynamic_compatibility() throws Exception {
+        assumeTrue(ClassFileVersion.ofThisVm().isAtLeast(JAVA_V11));
+
+        Class<?> typeWithCondy = new ByteBuddy()
+                .subclass(Callable.class)
+                .method(named("call"))
+                .intercept(FixedValue.value(JavaConstant.Dynamic.ofNullConstant()))
+                .make()
+                .load(null)
+                .getLoaded();
+
+        MockCreationSettings<?> settings = settingsFor(typeWithCondy);
+        @SuppressWarnings("unchecked")
+        Object proxy = mockMaker.createMock(settings, new MockHandlerImpl(settings));
+
+        assertThat(proxy.getClass()).isEqualTo(typeWithCondy);
+    }
+
     @Test
     public void test_clear_mock_clears_handler() {
         MockCreationSettings<GenericSubClass> settings = settingsFor(GenericSubClass.class);