Repository: mockito/mockito
Issue: Issue with mocking type in "java.util.*", Java 12
Labels: java-12

After upgrading Mockito from `2.23.4` to `2.24.0` we can't run JUnit 5's tests anymore. The error message reads:
```
    org.mockito.exceptions.base.MockitoException: 
    Mockito cannot mock this class: interface java.util.concurrent.locks.Lock.
    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.
```
Find the complete stacktrace here: https://travis-ci.org/junit-team/junit5/jobs/488684907

Note, that using Mockito `2.24.0` using Java 11 (and 13 locally) did work out! See this build matrix: https://travis-ci.org/junit-team/junit5/builds/488684905

Workaround: revert to Mockito `2.23.4` for the time being via https://github.com/junit-team/junit5/commit/754f1eb0f106ab043d79de546d49769690a731b6



Issue comments:
Suspiciously, the type is again in the `java.util` package. That leads me to believe any type definitive in there can't be mocked.
> That leads me to believe any type definitive in there can't be mocked.

Using `2.24.0`. It works with the older version.
The package should not be an issue, but I'll check. 
There is a dot missing after the package name....
Haha well spotted! Might be a simple String concatenation typo.
This is probably the mistake: https://github.com/mockito/mockito/blob/00cc06b387c3af8aaaed3a14fcb38df7d69db6c1/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java#L101

Should be:

```java
 typeName = InjectionBase.class.getPackage().getName() +"." + features.mockedType.getSimpleName();
```
Yes, very much.

Can it be that we don't have a test case for mocking a 'java.' type?

Are yoilu on your machine? I'll fix it next week otherwise. 
Sadly not. I can work on it tomorrow as well. Luckily we have a test suite now 🎉 
Or if @sormuras is available to make that PR, that would be amazing as well 😄 Our tests are specified in https://github.com/mockito/mockito/blob/f11705be91ee3545bc006908b34425f1fc359898/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
Great, Tim!

Any plans to sync current release to Maven Central, soon? 2.24.0 is the latest one that was uploaded: http://central.maven.org/maven2/org/mockito/mockito-core/maven-metadata.xml
I wanted to do so, but I first wanted to get some other issues resolved with @raphw Hopefully we can get to that next week. (but seems like we hit a JDK bug 🎉 )
Mockito 2.24.5 should be available on Maven central later today.
Looks good on 12: https://travis-ci.org/junit-team/junit5/jobs/495011557

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
index 8968b9e8e4..093978dd22 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
@@ -98,7 +98,7 @@ public <T> Class<? extends T> mockClass(MockFeatures<T> features) {
         if (localMock || loader instanceof MultipleParentClassLoader && !isComingFromJDK(features.mockedType)) {
             typeName = features.mockedType.getName();
         } else {
-            typeName = InjectionBase.class.getPackage().getName() + features.mockedType.getSimpleName();
+            typeName = InjectionBase.class.getPackage().getName() + "." + features.mockedType.getSimpleName();
         }
         String name = String.format("%s$%s$%d", typeName, "MockitoMock", Math.abs(random.nextInt()));
 


Test patch:
diff --git a/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java b/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java
index 240cf7d027..f8a262d15d 100644
--- a/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java
+++ b/src/test/java/org/mockitousage/serialization/AcrossClassLoaderSerializationTest.java
@@ -33,7 +33,7 @@ public void check_that_mock_can_be_serialized_in_a_classloader_and_deserialized_
         byte[] bytes = create_mock_and_serialize_it_in_class_loader_A();
 
         Object the_deserialized_mock = read_stream_and_deserialize_it_in_class_loader_B(bytes);
-        assertThat(the_deserialized_mock.getClass().getName()).startsWith("org.mockito.codegenAClassToBeMockedInThisTestOnlyAndInCallablesOnly");
+        assertThat(the_deserialized_mock.getClass().getName()).startsWith("org.mockito.codegen.AClassToBeMockedInThisTestOnlyAndInCallablesOnly");
     }
 
     private Object read_stream_and_deserialize_it_in_class_loader_B(byte[] bytes) throws Exception {
diff --git a/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java b/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
index 6ec32893a6..ed732c8089 100644
--- a/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
+++ b/subprojects/module-test/src/test/java/org/mockito/moduletest/ModuleHandlingTest.java
@@ -4,6 +4,7 @@
  */
 package org.mockito.moduletest;
 
+import java.util.concurrent.locks.Lock;
 import net.bytebuddy.ByteBuddy;
 import net.bytebuddy.description.modifier.Visibility;
 import net.bytebuddy.dynamic.loading.ClassInjector;
@@ -91,6 +92,34 @@ public void can_define_class_in_open_reading_module() throws Exception {
         }
     }
 
+    @Test
+    public void can_define_class_in_open_java_util_module() throws Exception {
+        assumeThat(Plugins.getMockMaker() instanceof InlineByteBuddyMockMaker, is(false));
+
+        Path jar = modularJar(true, true, true);
+        ModuleLayer layer = layer(jar, true);
+
+        ClassLoader loader = layer.findLoader("mockito.test");
+        Class<?> type = loader.loadClass("java.util.concurrent.locks.Lock");
+
+        ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(loader);
+        try {
+            Class<?> mockito = loader.loadClass(Mockito.class.getName());
+            @SuppressWarnings("unchecked")
+            Lock mock = (Lock) mockito.getMethod("mock", Class.class).invoke(null, type);
+            Object stubbing = mockito.getMethod("when", Object.class).invoke(null, mock.tryLock());
+            loader.loadClass(OngoingStubbing.class.getName()).getMethod("thenReturn", Object.class).invoke(stubbing, true);
+
+            boolean relocated = !Boolean.getBoolean("org.mockito.internal.noUnsafeInjection") && ClassInjector.UsingReflection.isAvailable();
+            String prefix = relocated ? "org.mockito.codegen.Lock$MockitoMock$" : "java.util.concurrent.locks.Lock$MockitoMock$";
+            assertThat(mock.getClass().getName()).startsWith(prefix);
+            assertThat(mock.tryLock()).isEqualTo(true);
+        } finally {
+            Thread.currentThread().setContextClassLoader(contextLoader);
+        }
+    }
+
     @Test
     public void inline_mock_maker_can_mock_closed_modules() throws Exception {
         assumeThat(Plugins.getMockMaker() instanceof InlineByteBuddyMockMaker, is(true));