Update to mockito 2.16.0

Test: atest CtsMockingTestCases CtsInlineMockingTestCases
Bug: 74344734
Change-Id: I20ac20aebdb4d7a184d85ad3657585b415f03b7f
diff --git a/Android.bp b/Android.bp
index 03d57ee..22e8cbf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,11 +35,7 @@
             // dexmaker instead and including it causes conflicts.
             exclude_srcs: [
                 "src/main/java/org/mockito/internal/creation/bytebuddy/**/*.java",
-                "src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java",
             ],
-            srcs: [
-                "stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java",
-            ]
         },
         host: {
             static_libs: [
diff --git a/README.version b/README.version
index 64b0bed..bbabbe6 100644
--- a/README.version
+++ b/README.version
@@ -1,5 +1,5 @@
 URL: https://github.com/mockito/mockito
-Version: v2.12.0
+Version: v2.16.0
 License: Apache 2.0
 Description: Mockito is a mocking framework with a clean and simple API.
 
@@ -9,4 +9,4 @@
 The source can be updated using the update_source.sh script.
 
 Local Modifications:
-	- Added dummy DefaultInvocationFactory to fix build
+        None
diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java
index 415df01..b25dae5 100644
--- a/src/main/java/org/mockito/Mockito.java
+++ b/src/main/java/org/mockito/Mockito.java
@@ -25,6 +25,7 @@
 import org.mockito.quality.MockitoHint;
 import org.mockito.quality.Strictness;
 import org.mockito.session.MockitoSessionBuilder;
+import org.mockito.session.MockitoSessionLogger;
 import org.mockito.stubbing.Answer;
 import org.mockito.stubbing.Answer1;
 import org.mockito.stubbing.OngoingStubbing;
@@ -96,6 +97,8 @@
  *      <a href="#40">40. (*new*) Improved productivity and cleaner tests with "stricter" Mockito (Since 2.+)</a><br/>
  *      <a href="#41">41. (**new**) Advanced public API for framework integrations (Since 2.10.+)</a><br/>
  *      <a href="#42">42. (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</a><br/>
+ *      <a href="#43">43. (**new**) New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a><br/>
+ *      <a href="#44">44. Deprecated <code>org.mockito.plugins.InstantiatorProvider</code> as it was leaking internal API. it was replaced by <code>org.mockito.plugins.InstantiatorProvider2 (Since 2.15.4)</code></a><br/>
  * </b>
  *
  * <h3 id="0">0. <a class="meaningful_link" href="#mockito2" name="mockito2">Migrating to Mockito 2</a></h3>
@@ -1396,7 +1399,7 @@
  * <a href="https://github.com/mockito/mockito/issues/769">issue 769</a>.
  *
  * <h3 id="41">41. <a class="meaningful_link" href="#framework_integrations_api" name="framework_integrations_api">
- *      (**new**) Advanced public API for framework integrations (Since 2.10.+)</h3>
+ *      (**new**) Advanced public API for framework integrations (Since 2.10.+)</a></h3>
  *
  * In Summer 2017 we decided that Mockito
  * <a href="https://www.linkedin.com/pulse/mockito-vs-powermock-opinionated-dogmatic-static-mocking-faber">
@@ -1449,7 +1452,7 @@
  * Do you have feedback? Please leave comment in <a href="https://github.com/mockito/mockito/issues/1110">issue 1110</a>.
  *
  * <h3 id="42">42. <a class="meaningful_link" href="#verifiation_started_listener" name="verifiation_started_listener">
- *       (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</h3>
+ *       (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</a></h3>
  *
  * Framework integrations such as <a href="https://projects.spring.io/spring-boot">Spring Boot</a> needs public API to tackle double-proxy use case
  * (<a href="https://github.com/mockito/mockito/issues/1191">issue 1191</a>).
@@ -1467,6 +1470,42 @@
  *     We found this method useful during the implementation.
  *     </li>
  * </ul>
+ *
+ * <h3 id="43">43. <a class="meaningful_link" href="#mockito_session_testing_frameworks" name="mockito_session_testing_frameworks">
+ *       (**new**) New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a></h3>
+ *
+ * <p>{@link MockitoSessionBuilder} and {@link MockitoSession} were enhanced to enable reuse by testing framework
+ * integrations (e.g. {@link MockitoRule} for JUnit):</p>
+ * <ul>
+ *     <li>{@link MockitoSessionBuilder#initMocks(Object...)} allows to pass in multiple test class instances for
+ *      initialization of fields annotated with Mockito annotations like {@link org.mockito.Mock}.
+ *      This method is useful for advanced framework integrations (e.g. JUnit Jupiter), when a test uses multiple,
+ *      e.g. nested, test class instances.
+ *     </li>
+ *     <li>{@link MockitoSessionBuilder#name(String)} allows to pass a name from the testing framework to the
+ *      {@link MockitoSession} that will be used for printing warnings when {@link Strictness#WARN} is used.
+ *     </li>
+ *     <li>{@link MockitoSessionBuilder#logger(MockitoSessionLogger)} makes it possible to customize the logger used
+ *      for hints/warnings produced when finishing mocking (useful for testing and to connect reporting capabilities
+ *      provided by testing frameworks such as JUnit Jupiter).
+ *     </li>
+ *     <li>{@link MockitoSession#setStrictness(Strictness)} allows to change the strictness of a {@link MockitoSession}
+ *      for one-off scenarios, e.g. it enables configuring a default strictness for all tests in a class but makes it
+ *      possible to change the strictness for a single or a few tests.
+ *     </li>
+ *     <li>{@link MockitoSession#finishMocking(Throwable)} was added to avoid confusion that may arise because
+ *      there are multiple competing failures. It will disable certain checks when the supplied <em>failure</em>
+ *      is not {@code null}.
+ *     </li>
+ * </ul>
+ *
+ * <h3 id="44">44. <a class="meaningful_link" href="#mockito_instantiator_provider_deprecation" name="mockito_instantiator_provider_deprecation">
+ *       Deprecated <code>org.mockito.plugins.InstantiatorProvider</code> as it was leaking internal API. it was
+ *       replaced by <code>org.mockito.plugins.InstantiatorProvider2 (Since 2.15.4)</a></h3>
+ *
+ * <p>{@link org.mockito.plugins.InstantiatorProvider} returned an internal API. Hence it was deprecated and replaced
+ * by {@link org.mockito.plugins.InstantiatorProvider2}. Old {@link org.mockito.plugins.InstantiatorProvider
+ * instantiator providers} will continue to work, but it is recommended to switch to the new API.</p>
  */
 @SuppressWarnings("unchecked")
 public class Mockito extends ArgumentMatchers {
@@ -1643,11 +1682,15 @@
      * // this calls the real implementation of Foo.getSomething()
      * value = mock.getSomething();
      *
-     * when(mock.getSomething()).thenReturn(fakeValue);
+     * doReturn(fakeValue).when(mock).getSomething();
      *
      * // now fakeValue is returned
      * value = mock.getSomething();
      * </code></pre>
+     *
+     * <p>
+     * <u>Note:</u> Stubbing partial mocks using <code>when(mock.getSomething()).thenReturn(fakeValue)</code>
+     * syntax will call the real method. For partial mock it's recommended to use <code>doReturn</code> syntax.
      */
     public static final Answer<Object> CALLS_REAL_METHODS = Answers.CALLS_REAL_METHODS;
 
@@ -2119,6 +2162,9 @@
      * See also {@link Mockito#never()} - it is more explicit and communicates the intent well.
      * <p>
      * Stubbed invocations (if called) are also treated as interactions.
+     * If you want stubbed invocations automatically verified, check out {@link Strictness#STRICT_STUBS} feature
+     * introduced in Mockito 2.3.0.
+     * If you want to ignore stubs for verification, see {@link #ignoreStubs(Object...)}.
      * <p>
      * A word of <b>warning</b>:
      * Some users who did a lot of classic, expect-run-verify mocking tend to use <code>verifyNoMoreInteractions()</code> very often, even in every test method.
diff --git a/src/main/java/org/mockito/MockitoSession.java b/src/main/java/org/mockito/MockitoSession.java
index 997a4fa..9e820f2 100644
--- a/src/main/java/org/mockito/MockitoSession.java
+++ b/src/main/java/org/mockito/MockitoSession.java
@@ -4,6 +4,7 @@
  */
 package org.mockito;
 
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
 import org.mockito.exceptions.misusing.UnfinishedMockingSessionException;
 import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -90,6 +91,20 @@
 public interface MockitoSession {
 
     /**
+     * Changes the strictness of this {@code MockitoSession}.
+     * The new strictness will be applied to operations on mocks and checks performed by {@link #finishMocking()}.
+     * This method is used behind the hood by {@link MockitoRule#strictness(Strictness)} method.
+     * In most healthy tests, this method is not needed.
+     * We keep it for edge cases and when you really need to change strictness in given test method.
+     * For use cases see Javadoc for {@link PotentialStubbingProblem} class.
+     *
+     * @param strictness new strictness for this session.
+     * @since 2.15.0
+     */
+    @Incubating
+    void setStrictness(Strictness strictness);
+
+    /**
      * Must be invoked when the user is done with mocking for given session (test method).
      * It detects unused stubbings and may throw {@link UnnecessaryStubbingException}
      * or emit warnings ({@link MockitoHint}) depending on the {@link Strictness} level.
@@ -105,8 +120,26 @@
      * <p>
      * For example, see javadoc for {@link MockitoSession}.
      *
+     * @see #finishMocking(Throwable)
      * @since 2.7.0
      */
     @Incubating
     void finishMocking();
+
+    /**
+     * Must be invoked when the user is done with mocking for given session (test method).
+     * When a {@linkplain Throwable failure} is specified, certain checks are disabled to avoid
+     * confusion that may arise because there are multiple competing failures. Other than that,
+     * this method behaves exactly like {@link #finishMocking()}.
+     * <p>
+     * This method is intended to be used by framework integrations. When using MockitoSession
+     * directly, most users should rather use {@link #finishMocking()}.
+     * {@link MockitoRule} uses this method behind the hood.
+     *
+     * @param failure the exception that caused the test to fail; passing {@code null} is permitted
+     * @see #finishMocking()
+     * @since 2.15.0
+     */
+    @Incubating
+    void finishMocking(Throwable failure);
 }
diff --git a/src/main/java/org/mockito/creation/instance/InstantiationException.java b/src/main/java/org/mockito/creation/instance/InstantiationException.java
new file mode 100644
index 0000000..1cfbaba
--- /dev/null
+++ b/src/main/java/org/mockito/creation/instance/InstantiationException.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.creation.instance;
+
+import org.mockito.exceptions.base.MockitoException;
+
+/**
+ * Exception generated when {@link Instantiator#newInstance(Class)} failed.
+ *
+ * @since 2.15.4
+ */
+public class InstantiationException extends MockitoException {
+
+    /**
+     * @since 2.15.4
+     */
+    public InstantiationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/org/mockito/creation/instance/Instantiator.java b/src/main/java/org/mockito/creation/instance/Instantiator.java
new file mode 100644
index 0000000..9ce37b5
--- /dev/null
+++ b/src/main/java/org/mockito/creation/instance/Instantiator.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.creation.instance;
+
+/**
+ * Provides instances of classes.
+ * See more information about Mockito plugin {@link org.mockito.plugins.InstantiatorProvider2}
+ *
+ * @since 2.15.4
+ */
+public interface Instantiator {
+
+    /**
+     * Creates instance of given class
+     *
+     * @since 2.15.4
+     */
+    <T> T newInstance(Class<T> cls) throws InstantiationException;
+
+}
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java b/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java
index 983e066..f80e7c4 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/DefaultMockitoPlugins.java
@@ -4,8 +4,10 @@
  */
 package org.mockito.internal.configuration.plugins;
 
+import org.mockito.internal.creation.instance.InstantiatorProvider2Adapter;
 import org.mockito.plugins.AnnotationEngine;
 import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
 import org.mockito.plugins.MockMaker;
 import org.mockito.plugins.MockitoPlugins;
 import org.mockito.plugins.PluginSwitch;
@@ -24,15 +26,22 @@
         DEFAULT_PLUGINS.put(PluginSwitch.class.getName(), DefaultPluginSwitch.class.getName());
         DEFAULT_PLUGINS.put(MockMaker.class.getName(), "org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker");
         DEFAULT_PLUGINS.put(StackTraceCleanerProvider.class.getName(), "org.mockito.internal.exceptions.stacktrace.DefaultStackTraceCleanerProvider");
-        DEFAULT_PLUGINS.put(InstantiatorProvider.class.getName(), "org.mockito.internal.creation.instance.DefaultInstantiatorProvider");
+        DEFAULT_PLUGINS.put(InstantiatorProvider2.class.getName(), "org.mockito.internal.creation.instance.DefaultInstantiatorProvider");
         DEFAULT_PLUGINS.put(AnnotationEngine.class.getName(), "org.mockito.internal.configuration.InjectingAnnotationEngine");
         DEFAULT_PLUGINS.put(INLINE_ALIAS, "org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker");
     }
 
     @Override
     public <T> T getDefaultPlugin(Class<T> pluginType) {
-        String className = DEFAULT_PLUGINS.get(pluginType.getName());
-        return create(pluginType, className);
+        if (pluginType == InstantiatorProvider.class) {
+            //the implementation class is not configured via map so that we can reduce duplication
+            //(ensure that we are adapting the currently configured default implementation for InstantiatorProvider2)
+            String className = DEFAULT_PLUGINS.get(InstantiatorProvider2.class.getName());
+            return pluginType.cast(new InstantiatorProvider2Adapter(create(InstantiatorProvider2.class, className)));
+        } else {
+            String className = DEFAULT_PLUGINS.get(pluginType.getName());
+            return create(pluginType, className);
+        }
     }
 
     String getDefaultPluginClass(String classOrAlias) {
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java b/src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java
new file mode 100644
index 0000000..0e28d91
--- /dev/null
+++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginInitializer.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.configuration.plugins;
+
+import org.mockito.internal.util.collections.Iterables;
+import org.mockito.plugins.PluginSwitch;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+class PluginInitializer {
+
+    private final PluginSwitch pluginSwitch;
+    private final String alias;
+    private final DefaultMockitoPlugins plugins;
+
+    PluginInitializer(PluginSwitch pluginSwitch, String alias, DefaultMockitoPlugins plugins) {
+        this.pluginSwitch = pluginSwitch;
+        this.alias = alias;
+        this.plugins = plugins;
+    }
+
+    /**
+     * Equivalent to {@link java.util.ServiceLoader#load} but without requiring
+     * Java 6 / Android 2.3 (Gingerbread).
+     */
+    public <T> T loadImpl(Class<T> service) {
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = ClassLoader.getSystemClassLoader();
+        }
+        Enumeration<URL> resources;
+        try {
+            resources = loader.getResources("mockito-extensions/" + service.getName());
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to load " + service, e);
+        }
+
+        try {
+            String classOrAlias = new PluginFinder(pluginSwitch).findPluginClass(Iterables.toIterable(resources));
+            if (classOrAlias != null) {
+                if (classOrAlias.equals(alias)) {
+                    classOrAlias = plugins.getDefaultPluginClass(alias);
+                }
+                Class<?> pluginClass = loader.loadClass(classOrAlias);
+                Object plugin = pluginClass.newInstance();
+                return service.cast(plugin);
+            }
+            return null;
+        } catch (Exception e) {
+            throw new IllegalStateException(
+                "Failed to load " + service + " implementation declared in " + resources, e);
+        }
+    }
+}
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java b/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java
index 0132dca..a230d0c 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginLoader.java
@@ -4,26 +4,24 @@
  */
 package org.mockito.internal.configuration.plugins;
 
-import org.mockito.internal.util.collections.Iterables;
 import org.mockito.plugins.PluginSwitch;
 
-import java.io.IOException;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
-import java.net.URL;
-import java.util.Enumeration;
 
 class PluginLoader {
 
-    private final DefaultMockitoPlugins plugins = new DefaultMockitoPlugins();
+    private final DefaultMockitoPlugins plugins;
+    private final PluginInitializer initializer;
 
-    private final PluginSwitch pluginSwitch;
+    PluginLoader(DefaultMockitoPlugins plugins, PluginInitializer initializer) {
+        this.plugins = plugins;
+        this.initializer = initializer;
+    }
 
-    private String alias;
-
-    public PluginLoader(PluginSwitch pluginSwitch) {
-        this.pluginSwitch = pluginSwitch;
+    PluginLoader(PluginSwitch pluginSwitch) {
+        this(new DefaultMockitoPlugins(), new PluginInitializer(pluginSwitch, null, new DefaultMockitoPlugins()));
     }
 
     /**
@@ -34,9 +32,8 @@
      * the alias can be used as a convenience name for a known plugin.
      */
     @Deprecated
-    PluginLoader withAlias(String name) {
-        alias = name;
-        return this;
+    PluginLoader(PluginSwitch pluginSwitch, String alias) {
+        this(new DefaultMockitoPlugins(), new PluginInitializer(pluginSwitch, alias, new DefaultMockitoPlugins()));
     }
 
     /**
@@ -44,55 +41,39 @@
      */
     @SuppressWarnings("unchecked")
     <T> T loadPlugin(final Class<T> pluginType) {
-        try {
-            T plugin = loadImpl(pluginType);
-            if (plugin != null) {
-                return plugin;
-            }
-
-            return plugins.getDefaultPlugin(pluginType);
-        } catch (final Throwable t) {
-            return (T) Proxy.newProxyInstance(pluginType.getClassLoader(),
-                    new Class<?>[]{pluginType},
-                    new InvocationHandler() {
-                        @Override
-                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                            throw new IllegalStateException("Could not initialize plugin: " + pluginType, t);
-                        }
-                    });
-        }
+        return (T) loadPlugin(pluginType, null);
     }
 
     /**
-     * Equivalent to {@link java.util.ServiceLoader#load} but without requiring
-     * Java 6 / Android 2.3 (Gingerbread).
+     * Scans the classpath for given {@code preferredPluginType}. If not found scan for {@code
+     * alternatePluginType}. If neither a preferred or alternate plugin is found, default to default
+     * class of {@code preferredPluginType}.
+     *
+     * @return An object of either {@code preferredPluginType} or {@code alternatePluginType}
      */
-    private <T> T loadImpl(Class<T> service) {
-        ClassLoader loader = Thread.currentThread().getContextClassLoader();
-        if (loader == null) {
-            loader = ClassLoader.getSystemClassLoader();
-        }
-        Enumeration<URL> resources;
+    @SuppressWarnings("unchecked")
+    <PreferredType, AlternateType> Object loadPlugin(final Class<PreferredType> preferredPluginType, final Class<AlternateType> alternatePluginType) {
         try {
-            resources = loader.getResources("mockito-extensions/" + service.getName());
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to load " + service, e);
-        }
-
-        try {
-            String classOrAlias = new PluginFinder(pluginSwitch).findPluginClass(Iterables.toIterable(resources));
-            if (classOrAlias != null) {
-                if (classOrAlias.equals(alias)) {
-                    classOrAlias = plugins.getDefaultPluginClass(alias);
+            PreferredType preferredPlugin = initializer.loadImpl(preferredPluginType);
+            if (preferredPlugin != null) {
+                return preferredPlugin;
+            } else if (alternatePluginType != null) {
+                AlternateType alternatePlugin = initializer.loadImpl(alternatePluginType);
+                if (alternatePlugin != null) {
+                    return alternatePlugin;
                 }
-                Class<?> pluginClass = loader.loadClass(classOrAlias);
-                Object plugin = pluginClass.newInstance();
-                return service.cast(plugin);
             }
-            return null;
-        } catch (Exception e) {
-            throw new IllegalStateException(
-                    "Failed to load " + service + " implementation declared in " + resources, e);
+
+            return plugins.getDefaultPlugin(preferredPluginType);
+        } catch (final Throwable t) {
+            return Proxy.newProxyInstance(preferredPluginType.getClassLoader(),
+                new Class<?>[]{preferredPluginType},
+                new InvocationHandler() {
+                    @Override
+                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                        throw new IllegalStateException("Could not initialize plugin: " + preferredPluginType + " (alternate: " + alternatePluginType + ")", t);
+                    }
+                });
         }
     }
 }
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java b/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java
index d75242c..02e5d66 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/PluginRegistry.java
@@ -4,8 +4,10 @@
  */
 package org.mockito.internal.configuration.plugins;
 
+import org.mockito.internal.creation.instance.InstantiatorProviderAdapter;
 import org.mockito.plugins.AnnotationEngine;
 import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
 import org.mockito.plugins.MockMaker;
 import org.mockito.plugins.PluginSwitch;
 import org.mockito.plugins.StackTraceCleanerProvider;
@@ -15,19 +17,26 @@
     private final PluginSwitch pluginSwitch = new PluginLoader(new DefaultPluginSwitch())
             .loadPlugin(PluginSwitch.class);
 
-    private final MockMaker mockMaker = new PluginLoader(pluginSwitch)
-            .withAlias(DefaultMockitoPlugins.INLINE_ALIAS)
+    private final MockMaker mockMaker = new PluginLoader(pluginSwitch, DefaultMockitoPlugins.INLINE_ALIAS)
             .loadPlugin(MockMaker.class);
 
     private final StackTraceCleanerProvider stackTraceCleanerProvider = new PluginLoader(pluginSwitch)
             .loadPlugin(StackTraceCleanerProvider.class);
 
-    private final InstantiatorProvider instantiatorProvider = new PluginLoader(pluginSwitch)
-            .loadPlugin(InstantiatorProvider.class);
+    private final InstantiatorProvider2 instantiatorProvider;
 
     private AnnotationEngine annotationEngine = new PluginLoader(pluginSwitch)
             .loadPlugin(AnnotationEngine.class);
 
+    PluginRegistry() {
+        Object impl = new PluginLoader(pluginSwitch).loadPlugin(InstantiatorProvider2.class, InstantiatorProvider.class);
+        if (impl instanceof InstantiatorProvider) {
+            instantiatorProvider = new InstantiatorProviderAdapter((InstantiatorProvider) impl);
+        } else {
+            instantiatorProvider = (InstantiatorProvider2) impl;
+        }
+    }
+
     /**
      * The implementation of the stack trace cleaner
      */
@@ -50,10 +59,11 @@
      * Returns the instantiator provider available for the current runtime.
      *
      * <p>Returns {@link org.mockito.internal.creation.instance.DefaultInstantiatorProvider} if no
-     * {@link org.mockito.plugins.InstantiatorProvider} extension exists or is visible in the current classpath.</p>
+     * {@link org.mockito.plugins.InstantiatorProvider2} extension exists or is visible in the
+     * current classpath.</p>
      */
-    InstantiatorProvider getInstantiatorProvider() {
-      return instantiatorProvider;
+    InstantiatorProvider2 getInstantiatorProvider() {
+        return instantiatorProvider;
     }
 
     /**
diff --git a/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java b/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java
index 2c214c2..f65fe89 100644
--- a/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java
+++ b/src/main/java/org/mockito/internal/configuration/plugins/Plugins.java
@@ -5,7 +5,7 @@
 package org.mockito.internal.configuration.plugins;
 
 import org.mockito.plugins.AnnotationEngine;
-import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
 import org.mockito.plugins.MockMaker;
 import org.mockito.plugins.MockitoPlugins;
 import org.mockito.plugins.StackTraceCleanerProvider;
@@ -38,9 +38,10 @@
      * Returns the instantiator provider available for the current runtime.
      *
      * <p>Returns {@link org.mockito.internal.creation.instance.DefaultInstantiatorProvider} if no
-     * {@link org.mockito.plugins.InstantiatorProvider} extension exists or is visible in the current classpath.</p>
+     * {@link org.mockito.plugins.InstantiatorProvider2} extension exists or is visible in the
+     * current classpath.</p>
      */
-    public static InstantiatorProvider getInstantiatorProvider() {
+    public static InstantiatorProvider2 getInstantiatorProvider() {
       return registry.getInstantiatorProvider();
     }
 
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
index 50d7851..42f10ce 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
@@ -9,7 +9,7 @@
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.exceptions.base.MockitoInitializationException;
 import org.mockito.internal.configuration.plugins.Plugins;
-import org.mockito.internal.creation.instance.Instantiator;
+import org.mockito.creation.instance.Instantiator;
 import org.mockito.internal.util.Platform;
 import org.mockito.internal.util.concurrent.WeakConcurrentMap;
 import org.mockito.invocation.MockHandler;
@@ -189,7 +189,7 @@
                 ((MockAccess) instance).setMockitoInterceptor(mockMethodInterceptor);
             }
             return instance;
-        } catch (org.mockito.internal.creation.instance.InstantiationException e) {
+        } catch (org.mockito.creation.instance.InstantiationException e) {
             throw new MockitoException("Unable to create mock instance of type '" + type.getSimpleName() + "'", e);
         }
     }
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java
index 7d9f347..f39a1a2 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodAdvice.java
@@ -16,6 +16,8 @@
 import org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter;
 import org.mockito.internal.invocation.RealMethod;
 import org.mockito.internal.invocation.SerializableMethod;
+import org.mockito.internal.invocation.mockref.MockReference;
+import org.mockito.internal.invocation.mockref.MockWeakReference;
 import org.mockito.internal.util.concurrent.WeakConcurrentMap;
 
 import java.io.IOException;
@@ -107,18 +109,20 @@
         return new ReturnValueWrapper(interceptor.doIntercept(instance,
                 origin,
                 arguments,
-            realMethod,
+                realMethod,
                 new LocationImpl(t)));
     }
 
     @Override
     public boolean isMock(Object instance) {
-        return interceptors.containsKey(instance);
+        // We need to exclude 'interceptors.target' explicitly to avoid a recursive check on whether
+        // the map is a mock object what requires reading from the map.
+        return instance != interceptors.target && interceptors.containsKey(instance);
     }
 
     @Override
     public boolean isMocked(Object instance) {
-        return !selfCallInfo.isSelfInvocation(instance) && isMock(instance);
+        return selfCallInfo.checkSuperCall(instance) && isMock(instance);
     }
 
     @Override
@@ -139,14 +143,14 @@
 
         private final Method origin;
 
-        private final Object instance;
+        private final MockWeakReference<Object> instanceRef;
 
         private final Object[] arguments;
 
         private RealMethodCall(SelfCallInfo selfCallInfo, Method origin, Object instance, Object[] arguments) {
             this.selfCallInfo = selfCallInfo;
             this.origin = origin;
-            this.instance = instance;
+            this.instanceRef = new MockWeakReference<Object>(instance);
             this.arguments = arguments;
         }
 
@@ -160,12 +164,8 @@
             if (!Modifier.isPublic(origin.getDeclaringClass().getModifiers() & origin.getModifiers())) {
                 origin.setAccessible(true);
             }
-            Object previous = selfCallInfo.replace(instance);
-            try {
-                return tryInvoke(origin, instance, arguments);
-            } finally {
-                selfCallInfo.set(previous);
-            }
+            selfCallInfo.set(instanceRef.get());
+            return tryInvoke(origin, instanceRef.get(), arguments);
         }
 
     }
@@ -176,14 +176,14 @@
 
         private final SerializableMethod origin;
 
-        private final Object instance;
+        private final MockReference<Object> instanceRef;
 
         private final Object[] arguments;
 
         private SerializableRealMethodCall(String identifier, Method origin, Object instance, Object[] arguments) {
             this.origin = new SerializableMethod(origin);
             this.identifier = identifier;
-            this.instance = instance;
+            this.instanceRef = new MockWeakReference<Object>(instance);
             this.arguments = arguments;
         }
 
@@ -198,13 +198,13 @@
             if (!Modifier.isPublic(method.getDeclaringClass().getModifiers() & method.getModifiers())) {
                 method.setAccessible(true);
             }
-            MockMethodDispatcher mockMethodDispatcher = MockMethodDispatcher.get(identifier, instance);
+            MockMethodDispatcher mockMethodDispatcher = MockMethodDispatcher.get(identifier, instanceRef.get());
             if (!(mockMethodDispatcher instanceof MockMethodAdvice)) {
                 throw new MockitoException("Unexpected dispatcher for advice-based super call");
             }
-            Object previous = ((MockMethodAdvice) mockMethodDispatcher).selfCallInfo.replace(instance);
+            Object previous = ((MockMethodAdvice) mockMethodDispatcher).selfCallInfo.replace(instanceRef.get());
             try {
-                return tryInvoke(method, instance, arguments);
+                return tryInvoke(method, instanceRef.get(), arguments);
             } finally {
                 ((MockMethodAdvice) mockMethodDispatcher).selfCallInfo.set(previous);
             }
@@ -252,14 +252,19 @@
 
     private static class SelfCallInfo extends ThreadLocal<Object> {
 
-        Object replace(Object instance) {
+        Object replace(Object value) {
             Object current = get();
-            set(instance);
+            set(value);
             return current;
         }
 
-        boolean isSelfInvocation(Object instance) {
-            return get() == instance;
+        boolean checkSuperCall(Object value) {
+            if (value == get()) {
+                set(null);
+                return false;
+            } else {
+                return true;
+            }
         }
     }
 
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
index 7c2dec8..9066927 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/MockMethodInterceptor.java
@@ -13,12 +13,8 @@
 import net.bytebuddy.implementation.bind.annotation.StubValue;
 import net.bytebuddy.implementation.bind.annotation.SuperCall;
 import net.bytebuddy.implementation.bind.annotation.This;
-import org.mockito.internal.creation.DelegatingMethod;
 import org.mockito.internal.debugging.LocationImpl;
-import org.mockito.internal.invocation.MockitoMethod;
 import org.mockito.internal.invocation.RealMethod;
-import org.mockito.internal.invocation.SerializableMethod;
-import org.mockito.internal.progress.SequenceNumber;
 import org.mockito.invocation.Location;
 import org.mockito.invocation.MockHandler;
 import org.mockito.mock.MockCreationSettings;
@@ -28,6 +24,8 @@
 import java.lang.reflect.Method;
 import java.util.concurrent.Callable;
 
+import static org.mockito.internal.invocation.DefaultInvocationFactory.createInvocation;
+
 public class MockMethodInterceptor implements Serializable {
 
     private static final long serialVersionUID = 7152947254057253027L;
@@ -65,29 +63,6 @@
         return handler.handle(createInvocation(mock, invokedMethod, arguments, realMethod, mockCreationSettings, location));
     }
 
-    public static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[] arguments, RealMethod realMethod, MockCreationSettings settings, Location location) {
-        return new InterceptedInvocation(
-            mock,
-            createMockitoMethod(invokedMethod, settings),
-            arguments,
-            realMethod,
-            location,
-            SequenceNumber.next()
-        );
-    }
-
-    public static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[] arguments, RealMethod realMethod, MockCreationSettings settings) {
-        return createInvocation(mock, invokedMethod, arguments, realMethod, settings, new LocationImpl());
-    }
-
-    private static MockitoMethod createMockitoMethod(Method method, MockCreationSettings settings) {
-        if (settings.isSerializable()) {
-            return new SerializableMethod(method);
-        } else {
-            return new DelegatingMethod(method);
-        }
-    }
-
     public MockHandler getMockHandler() {
         return handler;
     }
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java
index e9a3ddf..79e89f2 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassByteBuddyMockMaker.java
@@ -6,7 +6,7 @@
 
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.internal.configuration.plugins.Plugins;
-import org.mockito.internal.creation.instance.Instantiator;
+import org.mockito.creation.instance.Instantiator;
 import org.mockito.internal.util.Platform;
 import org.mockito.invocation.MockHandler;
 import org.mockito.mock.MockCreationSettings;
@@ -60,7 +60,7 @@
                     "You might experience classloading issues, please ask the mockito mailing-list.",
                     ""
             ), cce);
-        } catch (org.mockito.internal.creation.instance.InstantiationException e) {
+        } catch (org.mockito.creation.instance.InstantiationException e) {
             throw new MockitoException("Unable to create mock instance of type '" + mockedProxyType.getSuperclass().getSimpleName() + "'", e);
         }
     }
diff --git a/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java b/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java
index edf47c9..688526b 100644
--- a/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java
+++ b/src/main/java/org/mockito/internal/creation/instance/ConstructorInstantiator.java
@@ -10,6 +10,8 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.mockito.creation.instance.Instantiator;
+import org.mockito.creation.instance.InstantiationException;
 import org.mockito.internal.util.Primitives;
 import org.mockito.internal.util.reflection.AccessibilityChanger;
 
diff --git a/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java b/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java
index 22d06d1..9c414f3 100644
--- a/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java
+++ b/src/main/java/org/mockito/internal/creation/instance/DefaultInstantiatorProvider.java
@@ -4,10 +4,11 @@
  */
 package org.mockito.internal.creation.instance;
 
+import org.mockito.creation.instance.Instantiator;
 import org.mockito.mock.MockCreationSettings;
-import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
 
-public class DefaultInstantiatorProvider implements InstantiatorProvider {
+public class DefaultInstantiatorProvider implements InstantiatorProvider2 {
 
     private final static Instantiator INSTANCE = new ObjenesisInstantiator();
 
diff --git a/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java b/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java
index c0151f1..86b5463 100644
--- a/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java
+++ b/src/main/java/org/mockito/internal/creation/instance/InstantiationException.java
@@ -6,6 +6,14 @@
 
 import org.mockito.exceptions.base.MockitoException;
 
+/**
+ * @deprecated since 2.15.4 because this internal class was leaking from the public API.
+ * For information why deprecated, see {@link org.mockito.plugins.InstantiatorProvider2}.
+ * Use {@link org.mockito.creation.instance.Instantiator} and {@link org.mockito.creation.instance.InstantiationException} types instead.
+ * <p>
+ * Exception generated when {@link Instantiator#newInstance(Class)} failed.
+ */
+@Deprecated
 public class InstantiationException extends MockitoException {
 
     public InstantiationException(String message, Throwable cause) {
diff --git a/src/main/java/org/mockito/internal/creation/instance/Instantiator.java b/src/main/java/org/mockito/internal/creation/instance/Instantiator.java
index b1ee67d..85b6b3d 100644
--- a/src/main/java/org/mockito/internal/creation/instance/Instantiator.java
+++ b/src/main/java/org/mockito/internal/creation/instance/Instantiator.java
@@ -5,8 +5,13 @@
 package org.mockito.internal.creation.instance;
 
 /**
+ * @deprecated since 2.15.4 because this internal class was leaking from the public API.
+ * For more information why deprecated, see {@link org.mockito.plugins.InstantiatorProvider2}.
+ * Use {@link org.mockito.creation.instance.Instantiator} instead.
+ * <p>
  * Provides instances of classes.
  */
+@Deprecated
 public interface Instantiator {
 
     /**
diff --git a/src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java
new file mode 100644
index 0000000..a1ab5d5
--- /dev/null
+++ b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProvider2Adapter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.instance;
+
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
+
+/**
+ * Adapts new public API {@link InstantiatorProvider2} onto old, deprecated API {@link InstantiatorProvider}
+ */
+public class InstantiatorProvider2Adapter implements InstantiatorProvider {
+    private final InstantiatorProvider2 provider;
+
+    public InstantiatorProvider2Adapter(InstantiatorProvider2 provider) {
+        this.provider = provider;
+    }
+
+    @Override
+    public Instantiator getInstantiator(final MockCreationSettings<?> settings) {
+        return new Instantiator() {
+            @Override
+            public <T> T newInstance(Class<T> cls) throws InstantiationException {
+                try {
+                    return provider.getInstantiator(settings).newInstance(cls);
+                } catch (org.mockito.creation.instance.InstantiationException e) {
+                    throw new InstantiationException(e.getMessage(), e.getCause());
+                }
+            }
+        };
+    }
+}
diff --git a/src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java
new file mode 100644
index 0000000..c807925
--- /dev/null
+++ b/src/main/java/org/mockito/internal/creation/instance/InstantiatorProviderAdapter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.instance;
+
+import org.mockito.creation.instance.InstantiationException;
+import org.mockito.creation.instance.Instantiator;
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
+
+/**
+ * Adapts old, deprecated {@link InstantiatorProvider} onto a new public {@link InstantiatorProvider2} API.
+ */
+public class InstantiatorProviderAdapter implements InstantiatorProvider2 {
+    private final InstantiatorProvider provider;
+
+    public InstantiatorProviderAdapter(InstantiatorProvider provider) {
+        this.provider = provider;
+    }
+
+    @Override
+    public Instantiator getInstantiator(final MockCreationSettings<?> settings) {
+        return new Instantiator() {
+            @Override
+            public <T> T newInstance(Class<T> cls) throws InstantiationException {
+                try {
+                    return provider.getInstantiator(settings).newInstance(cls);
+                } catch (org.mockito.internal.creation.instance.InstantiationException e) {
+                    throw new InstantiationException(e.getMessage(), e.getCause());
+                }
+            }
+        };
+    }
+}
diff --git a/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java b/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java
index a0f0980..7e41f68 100644
--- a/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java
+++ b/src/main/java/org/mockito/internal/creation/instance/ObjenesisInstantiator.java
@@ -4,6 +4,7 @@
  */
 package org.mockito.internal.creation.instance;
 
+import org.mockito.creation.instance.Instantiator;
 import org.mockito.internal.configuration.GlobalConfiguration;
 import org.objenesis.ObjenesisStd;
 
diff --git a/src/main/java/org/mockito/internal/debugging/LocationImpl.java b/src/main/java/org/mockito/internal/debugging/LocationImpl.java
index ce3de04..8561b62 100644
--- a/src/main/java/org/mockito/internal/debugging/LocationImpl.java
+++ b/src/main/java/org/mockito/internal/debugging/LocationImpl.java
@@ -11,11 +11,14 @@
 public class LocationImpl implements Location, Serializable {
 
     private static final long serialVersionUID = -9054861157390980624L;
+    //Limit the amount of objects being created, as this class is heavily instantiated:
+    private static final StackTraceFilter defaultStackTraceFilter = new StackTraceFilter();
+
     private final Throwable stackTraceHolder;
     private final StackTraceFilter stackTraceFilter;
 
     public LocationImpl() {
-        this(new StackTraceFilter());
+        this(defaultStackTraceFilter);
     }
 
     public LocationImpl(StackTraceFilter stackTraceFilter) {
@@ -23,7 +26,7 @@
     }
 
     public LocationImpl(Throwable stackTraceHolder) {
-        this(new StackTraceFilter(), stackTraceHolder);
+        this(defaultStackTraceFilter, stackTraceHolder);
     }
 
     private LocationImpl(StackTraceFilter stackTraceFilter, Throwable stackTraceHolder) {
diff --git a/src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java b/src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java
deleted file mode 100644
index c8edc79..0000000
--- a/src/main/java/org/mockito/internal/exceptions/MockitoLimitations.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (c) 2016 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.exceptions;
-
-public class MockitoLimitations {
-
-    public final static String NON_PUBLIC_PARENT = "Mocking methods declared on non-public parent classes is not supported.";
-
-}
diff --git a/src/main/java/org/mockito/internal/exceptions/Reporter.java b/src/main/java/org/mockito/internal/exceptions/Reporter.java
index cee97fd..57094c0 100644
--- a/src/main/java/org/mockito/internal/exceptions/Reporter.java
+++ b/src/main/java/org/mockito/internal/exceptions/Reporter.java
@@ -51,6 +51,8 @@
  */
 public class Reporter {
 
+    private final static String NON_PUBLIC_PARENT = "Mocking methods declared on non-public parent classes is not supported.";
+
     private Reporter() {
     }
 
@@ -108,7 +110,7 @@
                 "Also, this error might show up because:",
                 "1. you stub either of: final/private/equals()/hashCode() methods.",
                 "   Those methods *cannot* be stubbed/verified.",
-                "   " + MockitoLimitations.NON_PUBLIC_PARENT,
+                "   " + NON_PUBLIC_PARENT,
                 "2. inside when() you don't call method on mock but on some other object.",
                 ""
         ));
@@ -124,7 +126,7 @@
                 "",
                 "Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.",
                 "Those methods *cannot* be stubbed/verified.",
-                MockitoLimitations.NON_PUBLIC_PARENT,
+                NON_PUBLIC_PARENT,
                 ""
         ));
     }
@@ -464,7 +466,7 @@
                 "2. Somewhere in your test you are stubbing *final methods*. Sorry, Mockito does not verify/stub final methods.",
                 "3. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - ",
                 "   - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.",
-                "4. " + MockitoLimitations.NON_PUBLIC_PARENT,
+                "4. " + NON_PUBLIC_PARENT,
                 ""
         ));
     }
@@ -531,7 +533,7 @@
                 "",
                 "Also, this error might show up because you use argument matchers with methods that cannot be mocked.",
                 "Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().",
-                MockitoLimitations.NON_PUBLIC_PARENT,
+                NON_PUBLIC_PARENT,
                 ""
         ));
     }
@@ -857,7 +859,7 @@
                 heading,
                 "Clean & maintainable test code requires zero unnecessary code.",
                 "Following stubbings are unnecessary (click to navigate to relevant line of code):" + stubbings,
-                "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class."
+                "Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class."
         ));
     }
 
@@ -888,7 +890,7 @@
                 "  - stubbing the same method multiple times using 'given().will()' or 'when().then()' API",
                 "    Please use 'will().given()' or 'doReturn().when()' API for stubbing.",
                 "  - stubbed method is intentionally invoked with different arguments by code under test",
-                "    Please use 'default' or 'silent' JUnit Rule.",
+                "    Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).",
                 "For more information see javadoc for PotentialStubbingProblem class."));
     }
 
diff --git a/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java b/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java
index 40b24bb..c900bf7 100644
--- a/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java
+++ b/src/main/java/org/mockito/internal/framework/DefaultMockitoSession.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.framework;
@@ -14,13 +14,17 @@
 import org.mockito.internal.util.MockitoLogger;
 import org.mockito.quality.Strictness;
 
+import java.util.List;
+
 public class DefaultMockitoSession implements MockitoSession {
 
-    private final Object testClassInstance;
+    private final List<Object> testClassInstances;
+    private final String name;
     private final UniversalTestListener listener;
 
-    public DefaultMockitoSession(Object testClassInstance, Strictness strictness, MockitoLogger logger) {
-        this.testClassInstance = testClassInstance;
+    public DefaultMockitoSession(List<Object> testClassInstances, String name, Strictness strictness, MockitoLogger logger) {
+        this.testClassInstances = testClassInstances;
+        this.name = name;
         listener = new UniversalTestListener(strictness, logger);
         try {
             //So that the listener can capture mock creation events
@@ -28,10 +32,23 @@
         } catch (RedundantListenerException e) {
             Reporter.unfinishedMockingSession();
         }
-        MockitoAnnotations.initMocks(testClassInstance);
+        for (Object testClassInstance : testClassInstances) {
+            MockitoAnnotations.initMocks(testClassInstance);
+        }
     }
 
+    @Override
+    public void setStrictness(Strictness strictness) {
+        listener.setStrictness(strictness);
+    }
+
+    @Override
     public void finishMocking() {
+        finishMocking(null);
+    }
+
+    @Override
+    public void finishMocking(final Throwable failure) {
         //Cleaning up the state, we no longer need the listener hooked up
         //The listener implements MockCreationListener and at this point
         //we no longer need to listen on mock creation events. We are wrapping up the session
@@ -39,18 +56,20 @@
 
         //Emit test finished event so that validation such as strict stubbing can take place
         listener.testFinished(new TestFinishedEvent() {
+            @Override
             public Throwable getFailure() {
-                return null;
+                return failure;
             }
-            public Object getTestClassInstance() {
-                return testClassInstance;
-            }
-            public String getTestMethodName() {
-                return null;
+            @Override
+            public String getTestName() {
+                return name;
             }
         });
 
-        //Finally, validate user's misuse of Mockito framework.
-        Mockito.validateMockitoUsage();
+        //Validate only when there is no test failure to avoid reporting multiple problems
+        if (failure == null) {
+            //Finally, validate user's misuse of Mockito framework.
+            Mockito.validateMockitoUsage();
+        }
     }
 }
diff --git a/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java b/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
index 38f18e9..57a9d43 100644
--- a/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
+++ b/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
@@ -8,7 +8,6 @@
 import org.mockito.internal.invocation.InvocationMatcher;
 import org.mockito.internal.invocation.MatchersBinder;
 import org.mockito.internal.listeners.StubbingLookupListener;
-import org.mockito.invocation.InvocationContainer;
 import org.mockito.internal.stubbing.InvocationContainerImpl;
 import org.mockito.internal.stubbing.OngoingStubbingImpl;
 import org.mockito.internal.stubbing.StubbedInvocationMatcher;
@@ -16,6 +15,7 @@
 import org.mockito.internal.verification.MockAwareVerificationMode;
 import org.mockito.internal.verification.VerificationDataImpl;
 import org.mockito.invocation.Invocation;
+import org.mockito.invocation.InvocationContainer;
 import org.mockito.invocation.MockHandler;
 import org.mockito.mock.MockCreationSettings;
 import org.mockito.verification.VerificationMode;
@@ -92,7 +92,14 @@
 
         if (stubbing != null) {
             stubbing.captureArgumentsFrom(invocation);
-            return stubbing.answer(invocation);
+
+            try {
+                return stubbing.answer(invocation);
+            } finally {
+                //Needed so that we correctly isolate stubbings in some scenarios
+                //see MockitoStubbedCallInAnswerTest or issue #1279
+                mockingProgress().reportOngoingStubbing(ongoingStubbing);
+            }
         } else {
             Object ret = mockSettings.getDefaultAnswer().answer(invocation);
             DefaultAnswerValidator.validateReturnValueFor(invocation, ret);
diff --git a/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java b/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
index af8fd3d..d08f6b1 100644
--- a/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
+++ b/src/main/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
@@ -4,9 +4,13 @@
  */
 package org.mockito.internal.invocation;
 
-import org.mockito.internal.creation.bytebuddy.MockMethodInterceptor;
+import org.mockito.internal.creation.DelegatingMethod;
+import org.mockito.internal.invocation.mockref.MockWeakReference;
+import org.mockito.internal.debugging.LocationImpl;
+import org.mockito.internal.progress.SequenceNumber;
 import org.mockito.invocation.Invocation;
 import org.mockito.invocation.InvocationFactory;
+import org.mockito.invocation.Location;
 import org.mockito.mock.MockCreationSettings;
 
 import java.lang.reflect.Method;
@@ -14,8 +18,41 @@
 
 public class DefaultInvocationFactory implements InvocationFactory {
 
-    public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, Callable realMethod, Object... args) {
-        RealMethod.FromCallable superMethod = new RealMethod.FromCallable(realMethod);
-        return MockMethodInterceptor.createInvocation(target, method, args, superMethod, settings);
+    public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, final Callable realMethod, Object... args) {
+        RealMethod superMethod = new RealMethod.FromCallable(realMethod);
+        return createInvocation(target, settings, method, superMethod, args);
+    }
+
+    public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, RealMethodBehavior realMethod, Object... args) {
+        RealMethod superMethod = new RealMethod.FromBehavior(realMethod);
+        return createInvocation(target, settings, method, superMethod, args);
+    }
+
+    private Invocation createInvocation(Object target, MockCreationSettings settings, Method method, RealMethod superMethod, Object[] args) {
+        return createInvocation(target, method, args, superMethod, settings);
+    }
+
+    public static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[] arguments, RealMethod realMethod, MockCreationSettings settings, Location location) {
+        return new InterceptedInvocation(
+            new MockWeakReference<Object>(mock),
+            createMockitoMethod(invokedMethod, settings),
+            arguments,
+            realMethod,
+            location,
+            SequenceNumber.next()
+        );
+    }
+
+    private static InterceptedInvocation createInvocation(Object mock, Method invokedMethod, Object[]
+        arguments, RealMethod realMethod, MockCreationSettings settings) {
+        return createInvocation(mock, invokedMethod, arguments, realMethod, settings, new LocationImpl());
+    }
+
+    private static MockitoMethod createMockitoMethod(Method method, MockCreationSettings settings) {
+        if (settings.isSerializable()) {
+            return new SerializableMethod(method);
+        } else {
+            return new DelegatingMethod(method);
+        }
     }
 }
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java b/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java
similarity index 91%
rename from src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java
rename to src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java
index 9c7b49e..b9cf072 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java
+++ b/src/main/java/org/mockito/internal/invocation/InterceptedInvocation.java
@@ -2,12 +2,10 @@
  * Copyright (c) 2016 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
-package org.mockito.internal.creation.bytebuddy;
+package org.mockito.internal.invocation;
 
+import org.mockito.internal.invocation.mockref.MockReference;
 import org.mockito.internal.exceptions.VerificationAwareInvocation;
-import org.mockito.internal.invocation.ArgumentsProcessor;
-import org.mockito.internal.invocation.MockitoMethod;
-import org.mockito.internal.invocation.RealMethod;
 import org.mockito.internal.reporting.PrintSettings;
 import org.mockito.invocation.Invocation;
 import org.mockito.invocation.Location;
@@ -22,7 +20,7 @@
 
     private static final long serialVersionUID = 475027563923510472L;
 
-    private final Object mock;
+    private final MockReference<Object> mockRef;
     private final MockitoMethod mockitoMethod;
     private final Object[] arguments, rawArguments;
     private final RealMethod realMethod;
@@ -35,13 +33,13 @@
     private boolean isIgnoredForVerification;
     private StubInfo stubInfo;
 
-    public InterceptedInvocation(Object mock,
+    public InterceptedInvocation(MockReference<Object> mockRef,
                                  MockitoMethod mockitoMethod,
                                  Object[] arguments,
                                  RealMethod realMethod,
                                  Location location,
                                  int sequenceNumber) {
-        this.mock = mock;
+        this.mockRef = mockRef;
         this.mockitoMethod = mockitoMethod;
         this.arguments = ArgumentsProcessor.expandArgs(mockitoMethod, arguments);
         this.rawArguments = arguments;
@@ -102,7 +100,7 @@
 
     @Override
     public Object getMock() {
-        return mock;
+        return mockRef.get();
     }
 
     @Override
@@ -141,7 +139,7 @@
             return false;
         }
         InterceptedInvocation other = (InterceptedInvocation) o;
-        return this.mock.equals(other.mock)
+        return this.mockRef.get().equals(other.mockRef.get())
                 && this.mockitoMethod.equals(other.mockitoMethod)
                 && this.equalArguments(other.arguments);
     }
diff --git a/src/main/java/org/mockito/internal/invocation/RealMethod.java b/src/main/java/org/mockito/internal/invocation/RealMethod.java
index cd74d3c..b7c8c17 100644
--- a/src/main/java/org/mockito/internal/invocation/RealMethod.java
+++ b/src/main/java/org/mockito/internal/invocation/RealMethod.java
@@ -5,6 +5,7 @@
 package org.mockito.internal.invocation;
 
 import org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter;
+import org.mockito.invocation.InvocationFactory;
 import org.mockito.invocation.InvocationOnMock;
 
 import java.io.Serializable;
@@ -31,14 +32,23 @@
         }
     }
 
-    class FromCallable implements RealMethod {
+    class FromCallable extends FromBehavior implements RealMethod {
+        public FromCallable(final Callable<?> callable) {
+            super(new InvocationFactory.RealMethodBehavior() {
+                @Override
+                public Object call() throws Throwable {
+                    return callable.call();
+                }
+            });
+        }
+    }
 
-        private static final long serialVersionUID = 47957363950483625L;
+    class FromBehavior implements RealMethod {
 
-        private final Callable<?> callable;
+        private final InvocationFactory.RealMethodBehavior<?> behavior;
 
-        public FromCallable(Callable<?> callable) {
-            this.callable = callable;
+        FromBehavior(InvocationFactory.RealMethodBehavior<?> behavior) {
+            this.behavior = behavior;
         }
 
         @Override
@@ -49,7 +59,7 @@
         @Override
         public Object invoke() throws Throwable {
             try {
-                return callable.call();
+                return behavior.call();
             } catch (Throwable t) {
                 new ConditionalStackTraceFilter().filter(t);
                 throw t;
diff --git a/src/main/java/org/mockito/internal/invocation/mockref/MockReference.java b/src/main/java/org/mockito/internal/invocation/mockref/MockReference.java
new file mode 100644
index 0000000..0dac2ea
--- /dev/null
+++ b/src/main/java/org/mockito/internal/invocation/mockref/MockReference.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.invocation.mockref;
+
+import java.io.Serializable;
+
+/**
+ * To avoid memory leaks for certain implementations of MockMaker,
+ * we need to use weak mock references internally. See #1313
+ */
+public interface MockReference<T> extends Serializable {
+    T get();
+}
diff --git a/src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java b/src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java
new file mode 100644
index 0000000..3b20ee5
--- /dev/null
+++ b/src/main/java/org/mockito/internal/invocation/mockref/MockStrongReference.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.invocation.mockref;
+
+import java.io.ObjectStreamException;
+
+public class MockStrongReference<T> implements MockReference<T> {
+
+    private final T ref;
+    private final boolean deserializeAsWeakRef;
+
+    public MockStrongReference(T ref, boolean deserializeAsWeakRef) {
+        this.ref = ref;
+        this.deserializeAsWeakRef = deserializeAsWeakRef;
+    }
+
+    @Override
+    public T get() {
+        return ref;
+    }
+
+    private Object readResolve() throws ObjectStreamException {
+        if (deserializeAsWeakRef) {
+            return new MockWeakReference<T>(ref);
+        } else {
+            return this;
+        }
+    }
+}
diff --git a/src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java b/src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java
new file mode 100644
index 0000000..256745b
--- /dev/null
+++ b/src/main/java/org/mockito/internal/invocation/mockref/MockWeakReference.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.invocation.mockref;
+
+import java.io.ObjectStreamException;
+import java.lang.ref.WeakReference;
+
+/**
+ * A weak reference that is converted into a strong reference when serialized.
+ * See {@link MockReference}.
+ */
+public class MockWeakReference<T> implements MockReference<T> {
+
+    private final WeakReference<T> ref;
+
+    public MockWeakReference(T t) {
+        this.ref = new WeakReference<T>(t);
+    }
+
+    private Object writeReplace() throws ObjectStreamException {
+        return new MockStrongReference<T>(get(), true);
+    }
+
+    @Override
+    public T get() {
+        T ref = this.ref.get();
+
+        if (ref == null) {
+            throw new IllegalStateException("The mock object was garbage collected. " +
+                "This should not happen in normal circumstances when using public API. " +
+                "Typically, the test class keeps strong reference to the mock object " +
+                "and it prevents getting the mock collected. Mockito internally needs " +
+                "to keep weak references to mock objects to avoid memory leaks for " +
+                "certain types of MockMaker implementations. If you see this exception " +
+                "using Mockito public API, please file a bug. For more information see " +
+                "issue #1313.");
+        }
+
+        return ref;
+    }
+}
diff --git a/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java b/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java
index 172868c..c3b348b 100644
--- a/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java
+++ b/src/main/java/org/mockito/internal/junit/DefaultTestFinishedEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.junit;
@@ -15,15 +15,13 @@
         this.testFailure = testFailure;
     }
 
+    @Override
     public Throwable getFailure() {
         return testFailure;
     }
 
-    public Object getTestClassInstance() {
-        return testClassInstance;
-    }
-
-    public String getTestMethodName() {
-        return testMethodName;
+    @Override
+    public String getTestName() {
+        return testClassInstance.getClass().getSimpleName() + "." + testMethodName;
     }
 }
diff --git a/src/main/java/org/mockito/internal/junit/JUnitRule.java b/src/main/java/org/mockito/internal/junit/JUnitRule.java
index 8763354..b825416 100644
--- a/src/main/java/org/mockito/internal/junit/JUnitRule.java
+++ b/src/main/java/org/mockito/internal/junit/JUnitRule.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.junit;
@@ -7,9 +7,10 @@
 import org.junit.runners.model.FrameworkMethod;
 import org.junit.runners.model.Statement;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.quality.Strictness;
+import org.mockito.MockitoSession;
+import org.mockito.internal.session.MockitoSessionLoggerAdapter;
 import org.mockito.internal.util.MockitoLogger;
+import org.mockito.quality.Strictness;
 import org.mockito.junit.MockitoRule;
 
 /**
@@ -18,44 +19,32 @@
 public class JUnitRule implements MockitoRule {
 
     private final MockitoLogger logger;
-    private final UniversalTestListener listener;
+    private Strictness strictness;
+    private MockitoSession session;
 
     /**
-     * @param logger target for the stubbing warnings
      * @param strictness how strict mocking / stubbing is concerned
      */
     public JUnitRule(MockitoLogger logger, Strictness strictness) {
         this.logger = logger;
-        this.listener = new UniversalTestListener(strictness, logger);
+        this.strictness = strictness;
     }
 
 	@Override
 	public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
         return new Statement() {
             public void evaluate() throws Throwable {
-                //Ideally, JUnit rule should use MockitoSession API so that it dogfoods our public API.
-                //See https://github.com/mockito/mockito/issues/898
-                Mockito.framework().addListener(listener);
-                Throwable testFailure;
-                try {
-                    //mock initialization could be part of listeners but to avoid duplication I left it here:
-                    MockitoAnnotations.initMocks(target);
-                    testFailure = evaluateSafely(base);
-                } finally {
-                    Mockito.framework().removeListener(listener);
-                }
-
-                //If the 'testFinished' fails below, we don't see the original failure, thrown later
-                DefaultTestFinishedEvent event = new DefaultTestFinishedEvent(target, method.getName(), testFailure);
-                listener.testFinished(event);
-
+                session = Mockito.mockitoSession()
+                    .name(target.getClass().getSimpleName() + "." + method.getName())
+                    .strictness(strictness)
+                    .logger(new MockitoSessionLoggerAdapter(logger))
+                    .initMocks(target)
+                    .startMocking();
+                Throwable testFailure = evaluateSafely(base);
+                session.finishMocking(testFailure);
                 if (testFailure != null) {
                     throw testFailure;
                 }
-
-                //Validate only when there is no test failure to avoid reporting multiple problems
-                //This could be part of the listener but to avoid duplication I left it here:
-                Mockito.validateMockitoUsage();
             }
 
             private Throwable evaluateSafely(Statement base) {
@@ -70,11 +59,16 @@
     }
 
     public MockitoRule silent() {
-        return new JUnitRule(logger, Strictness.LENIENT);
+        return strictness(Strictness.LENIENT);
     }
 
     public MockitoRule strictness(Strictness strictness) {
-        this.listener.setStrictness(strictness);
+        this.strictness = strictness;
+        // session is null when this method is called during initialization of
+        // the @Rule field of the test class
+        if (session != null) {
+            session.setStrictness(strictness);
+        }
         return this;
     }
 }
diff --git a/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java b/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java
index 408c581..26d4e4e 100644
--- a/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java
+++ b/src/main/java/org/mockito/internal/junit/MismatchReportingTestListener.java
@@ -1,10 +1,9 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.junit;
 
-import org.mockito.internal.junit.util.TestName;
 import org.mockito.internal.util.MockitoLogger;
 import org.mockito.mock.MockCreationSettings;
 
@@ -30,10 +29,9 @@
         //TODO make it better, it's easy to forget to clean up mocks and we still create new instance of list that nobody will read, it's also duplicated
         mocks = new LinkedList<Object>();
 
-        String testName = TestName.getTestName(event);
         if (event.getFailure() != null) {
             //print unused stubbings only when test succeeds to avoid reporting multiple problems and confusing users
-            new ArgMismatchFinder().getStubbingArgMismatches(createdMocks).format(testName, logger);
+            new ArgMismatchFinder().getStubbingArgMismatches(createdMocks).format(event.getTestName(), logger);
         }
     }
 
diff --git a/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java b/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java
index 18b099a..43b373a 100644
--- a/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java
+++ b/src/main/java/org/mockito/internal/junit/TestFinishedEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.junit;
@@ -8,8 +8,6 @@
 
     Throwable getFailure();
 
-    Object getTestClassInstance();
-
-    String getTestMethodName();
+    String getTestName();
 
 }
diff --git a/src/main/java/org/mockito/internal/junit/UniversalTestListener.java b/src/main/java/org/mockito/internal/junit/UniversalTestListener.java
index 8db020b..66c9dee 100644
--- a/src/main/java/org/mockito/internal/junit/UniversalTestListener.java
+++ b/src/main/java/org/mockito/internal/junit/UniversalTestListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.junit;
@@ -60,14 +60,13 @@
     }
 
     private static void emitWarnings(MockitoLogger logger, TestFinishedEvent event, Collection<Object> mocks) {
-        String testName = event.getTestClassInstance().getClass().getSimpleName() + "." + event.getTestMethodName();
         if (event.getFailure() != null) {
             //print stubbing mismatches only when there is a test failure
             //to avoid false negatives. Give hint only when test fails.
-            new ArgMismatchFinder().getStubbingArgMismatches(mocks).format(testName, logger);
+            new ArgMismatchFinder().getStubbingArgMismatches(mocks).format(event.getTestName(), logger);
         } else {
             //print unused stubbings only when test succeeds to avoid reporting multiple problems and confusing users
-            new UnusedStubbingsFinder().getUnusedStubbings(mocks).format(testName, logger);
+            new UnusedStubbingsFinder().getUnusedStubbings(mocks).format(event.getTestName(), logger);
         }
     }
 
diff --git a/src/main/java/org/mockito/internal/junit/util/TestName.java b/src/main/java/org/mockito/internal/junit/util/TestName.java
deleted file mode 100644
index 6f09937..0000000
--- a/src/main/java/org/mockito/internal/junit/util/TestName.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2017 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.junit.util;
-
-import org.mockito.internal.junit.TestFinishedEvent;
-
-/**
- * Provides test name
- */
-public class TestName {
-
-    public static String getTestName(TestFinishedEvent event) {
-        return event.getTestClassInstance().getClass().getSimpleName() + "." + event.getTestMethodName();
-    }
-}
diff --git a/src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java b/src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java
deleted file mode 100644
index 32d3c66..0000000
--- a/src/main/java/org/mockito/internal/matchers/text/ArrayIterator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2016 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.matchers.text;
-
-import java.lang.reflect.Array;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * Inspired on hamcrest, internal package class,
- * TODO add specific unit tests instead of relying on higher level unit tests
- */
-class ArrayIterator implements Iterator<Object> {
-
-    private final Object array;
-    private int currentIndex = 0;
-
-    public ArrayIterator(Object array) {
-        if (array == null) {
-            //TODO extract a small utility for null-checking
-            throw new IllegalArgumentException("Expected array instance but got null");
-        }
-        if (!array.getClass().isArray()) {
-            throw new IllegalArgumentException("Expected array but got object of type: "
-                    + array.getClass() + ", the object: " + array.toString());
-        }
-        this.array = array;
-    }
-
-    public boolean hasNext() {
-        return currentIndex < Array.getLength(array);
-    }
-
-    public Object next() {
-        if (!hasNext()) {
-            throw new NoSuchElementException();
-        }
-        return Array.get(array, currentIndex++);
-    }
-
-    public void remove() {
-        throw new UnsupportedOperationException("cannot remove items from an array");
-    }
-}
diff --git a/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java b/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java
index f741cbc..6f5882f 100644
--- a/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java
+++ b/src/main/java/org/mockito/internal/matchers/text/ValuePrinter.java
@@ -4,6 +4,7 @@
  */
 package org.mockito.internal.matchers.text;
 
+import java.lang.reflect.Array;
 import java.util.Iterator;
 import java.util.Map;
 
@@ -21,7 +22,7 @@
      * Prints given value so that it is neatly readable by humans.
      * Handles explosive toString() implementations.
      */
-    public static String print(Object value) {
+    public static String print(final Object value) {
         if (value == null) {
             return "null";
         }
@@ -50,7 +51,21 @@
             return printMap((Map<?, ?>) value);
         }
         if (value.getClass().isArray()) {
-            return printValues("[", ", ", "]", new ArrayIterator(value));
+            return printValues("[", ", ", "]", new Iterator<Object>() {
+                private int currentIndex = 0;
+
+                public boolean hasNext() {
+                    return currentIndex < Array.getLength(value);
+                }
+
+                public Object next() {
+                    return Array.get(value, currentIndex++);
+                }
+
+                public void remove() {
+                    throw new UnsupportedOperationException("cannot remove items from an array");
+                }
+            });
         }
         if (value instanceof FormattedText) {
             return (((FormattedText) value).getText());
diff --git a/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java b/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java
index a0f8c66..2685ddf 100644
--- a/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java
+++ b/src/main/java/org/mockito/internal/progress/MockingProgressImpl.java
@@ -47,8 +47,8 @@
         };
     }
 
-    public void reportOngoingStubbing(OngoingStubbing iOngoingStubbing) {
-        this.ongoingStubbing = iOngoingStubbing;
+    public void reportOngoingStubbing(OngoingStubbing ongoingStubbing) {
+        this.ongoingStubbing = ongoingStubbing;
     }
 
     public OngoingStubbing<?> pullOngoingStubbing() {
@@ -129,7 +129,7 @@
     }
 
     public String toString() {
-        return  "iOngoingStubbing: " + ongoingStubbing +
+        return  "ongoingStubbing: " + ongoingStubbing +
         ", verificationMode: " + verificationMode +
         ", stubbingInProgress: " + stubbingInProgress;
     }
diff --git a/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java b/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java
index 897e613..2f26ff1 100644
--- a/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java
+++ b/src/main/java/org/mockito/internal/runners/DefaultInternalRunner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.runners;
@@ -16,6 +16,7 @@
 import org.junit.runners.model.Statement;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.internal.junit.DefaultTestFinishedEvent;
 import org.mockito.internal.junit.MockitoTestListener;
 import org.mockito.internal.util.Supplier;
 
diff --git a/src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java b/src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java
deleted file mode 100644
index 2eee23f..0000000
--- a/src/main/java/org/mockito/internal/runners/DefaultTestFinishedEvent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2017 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.runners;
-
-import org.mockito.internal.junit.TestFinishedEvent;
-
-class DefaultTestFinishedEvent implements TestFinishedEvent {
-
-    private final Object testClassInstance;
-    private final String testMethodName;
-    private final Throwable failure;
-
-    DefaultTestFinishedEvent(Object testClassInstance, String testMethodName, Throwable failure) {
-        this.testClassInstance = testClassInstance;
-        this.testMethodName = testMethodName;
-        this.failure = failure;
-    }
-
-    @Override
-    public Object getTestClassInstance() {
-        return testClassInstance;
-    }
-
-    @Override
-    public String getTestMethodName() {
-        return testMethodName;
-    }
-
-    @Override
-    public Throwable getFailure() {
-        return failure;
-    }
-}
diff --git a/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java b/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java
index bfd6be8..d9b21e5 100644
--- a/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java
+++ b/src/main/java/org/mockito/internal/session/DefaultMockitoSessionBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.session;
@@ -7,17 +7,44 @@
 import org.mockito.MockitoSession;
 import org.mockito.internal.framework.DefaultMockitoSession;
 import org.mockito.internal.util.ConsoleMockitoLogger;
+import org.mockito.internal.util.MockitoLogger;
 import org.mockito.quality.Strictness;
 import org.mockito.session.MockitoSessionBuilder;
+import org.mockito.session.MockitoSessionLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Collections.emptyList;
 
 public class DefaultMockitoSessionBuilder implements MockitoSessionBuilder {
 
-    private Object testClassInstance;
+    private List<Object> testClassInstances = new ArrayList<Object>();
+    private String name;
     private Strictness strictness;
+    private MockitoSessionLogger logger;
 
     @Override
     public MockitoSessionBuilder initMocks(Object testClassInstance) {
-        this.testClassInstance = testClassInstance;
+        if (testClassInstance != null) {
+            this.testClassInstances.add(testClassInstance);
+        }
+        return this;
+    }
+
+    @Override
+    public MockitoSessionBuilder initMocks(Object... testClassInstances) {
+        if (testClassInstances != null) {
+            for (Object instance : testClassInstances) {
+                initMocks(instance);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public MockitoSessionBuilder name(String name) {
+        this.name = name;
         return this;
     }
 
@@ -28,10 +55,26 @@
     }
 
     @Override
+    public MockitoSessionBuilder logger(MockitoSessionLogger logger) {
+        this.logger = logger;
+        return this;
+    }
+
+    @Override
     public MockitoSession startMocking() {
         //Configure default values
-        Object effectiveTest = this.testClassInstance == null ? new Object() : this.testClassInstance;
+        List<Object> effectiveTestClassInstances;
+        String effectiveName;
+        if (testClassInstances.isEmpty()) {
+            effectiveTestClassInstances = emptyList();
+            effectiveName = this.name == null ? "<Unnamed Session>" : this.name;
+        } else {
+            effectiveTestClassInstances = new ArrayList<Object>(testClassInstances);
+            Object lastTestClassInstance = testClassInstances.get(testClassInstances.size() - 1);
+            effectiveName = this.name == null ? lastTestClassInstance.getClass().getName() : this.name;
+        }
         Strictness effectiveStrictness = this.strictness == null ? Strictness.STRICT_STUBS : this.strictness;
-        return new DefaultMockitoSession(effectiveTest, effectiveStrictness, new ConsoleMockitoLogger());
+        MockitoLogger logger = this.logger == null ? new ConsoleMockitoLogger() : new MockitoLoggerAdapter(this.logger);
+        return new DefaultMockitoSession(effectiveTestClassInstances, effectiveName, effectiveStrictness, logger);
     }
 }
diff --git a/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java b/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java
new file mode 100644
index 0000000..b7329e7
--- /dev/null
+++ b/src/main/java/org/mockito/internal/session/MockitoLoggerAdapter.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.session;
+
+import org.mockito.internal.util.MockitoLogger;
+import org.mockito.session.MockitoSessionLogger;
+
+class MockitoLoggerAdapter implements MockitoLogger {
+
+    private final MockitoSessionLogger logger;
+
+    MockitoLoggerAdapter(MockitoSessionLogger logger) {
+        this.logger = logger;
+    }
+
+    @Override
+    public void log(Object what) {
+        logger.log(String.valueOf(what));
+    }
+}
diff --git a/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java b/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java
new file mode 100644
index 0000000..2e8634b
--- /dev/null
+++ b/src/main/java/org/mockito/internal/session/MockitoSessionLoggerAdapter.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.session;
+
+import org.mockito.internal.util.MockitoLogger;
+import org.mockito.session.MockitoSessionLogger;
+
+public class MockitoSessionLoggerAdapter implements MockitoSessionLogger {
+
+    private final MockitoLogger logger;
+
+    public MockitoSessionLoggerAdapter(MockitoLogger logger) {
+        this.logger = logger;
+    }
+
+    @Override
+    public void log(String hint) {
+        logger.log(hint);
+    }
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java b/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
index f88fc03..120320b 100644
--- a/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
@@ -4,11 +4,6 @@
  */
 package org.mockito.internal.stubbing;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
 import org.mockito.internal.invocation.StubInfoImpl;
 import org.mockito.internal.verification.DefaultRegisteredInvocations;
 import org.mockito.internal.verification.RegisteredInvocations;
@@ -21,6 +16,11 @@
 import org.mockito.stubbing.Stubbing;
 import org.mockito.stubbing.ValidableAnswer;
 
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
 import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
 
 @SuppressWarnings("unchecked")
@@ -93,10 +93,6 @@
         return null;
     }
 
-    public void addAnswerForVoidMethod(Answer answer) {
-        answersForStubbing.add(answer);
-    }
-
     public void setAnswersForStubbing(List<Answer<?>> answers) {
         answersForStubbing.addAll(answers);
     }
diff --git a/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java b/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java
index 7296095..25e8be7 100644
--- a/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java
+++ b/src/main/java/org/mockito/internal/stubbing/answers/ClonesArguments.java
@@ -5,7 +5,7 @@
 package org.mockito.internal.stubbing.answers;
 
 import org.mockito.internal.configuration.plugins.Plugins;
-import org.mockito.internal.creation.instance.Instantiator;
+import org.mockito.creation.instance.Instantiator;
 import org.mockito.internal.stubbing.defaultanswers.ReturnsEmptyValues;
 import org.mockito.internal.util.reflection.LenientCopyTool;
 import org.mockito.invocation.InvocationOnMock;
diff --git a/src/main/java/org/mockito/internal/util/collections/Sets.java b/src/main/java/org/mockito/internal/util/collections/Sets.java
index a5a80f1..f1972e9 100644
--- a/src/main/java/org/mockito/internal/util/collections/Sets.java
+++ b/src/main/java/org/mockito/internal/util/collections/Sets.java
@@ -18,10 +18,6 @@
         return HashCodeAndEqualsSafeSet.of(mocks);
     }
 
-    public static IdentitySet newIdentitySet() {
-        return new IdentitySet();
-    }
-
     public static <T> Set<T> newSet(T ... elements) {
         if (elements == null) {
             throw new IllegalArgumentException("Expected an array of elements (or empty array) but received a null.");
diff --git a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
index c147693..b411a73 100644
--- a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
+++ b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
@@ -26,7 +26,7 @@
 
     private static final AtomicLong ID = new AtomicLong();
 
-    final ConcurrentMap<WeakKey<K>, V> target;
+    public final ConcurrentMap<WeakKey<K>, V> target;
 
     private final Thread thread;
 
diff --git a/src/main/java/org/mockito/invocation/InvocationFactory.java b/src/main/java/org/mockito/invocation/InvocationFactory.java
index 8339642..1803718 100644
--- a/src/main/java/org/mockito/invocation/InvocationFactory.java
+++ b/src/main/java/org/mockito/invocation/InvocationFactory.java
@@ -8,6 +8,7 @@
 import org.mockito.MockitoFramework;
 import org.mockito.mock.MockCreationSettings;
 
+import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.util.concurrent.Callable;
 
@@ -19,7 +20,7 @@
  * <p>
  * Please don't provide your own implementation of {@link Invocation} type.
  * Mockito team needs flexibility to add new methods to this interface if we need to.
- * If you integrate Mockito framework and you need an instance of {@link Invocation}, use {@link #createInvocation(Object, MockCreationSettings, Method, Callable, Object...)}.
+ * If you integrate Mockito framework and you need an instance of {@link Invocation}, use {@link #createInvocation(Object, MockCreationSettings, Method, RealMethodBehavior, Object...)}.
  *
  * @since 2.10.0
  */
@@ -27,6 +28,11 @@
 public interface InvocationFactory {
 
     /**
+     * @deprecated Use {@link #createInvocation(Object, MockCreationSettings, Method, RealMethodBehavior, Object...)} instead.
+     *
+     * Why deprecated? We found use cases where we need to handle Throwable and ensure correct stack trace filtering
+     * (removing Mockito internals from the stack trace). Hence the introduction of {@link RealMethodBehavior}.
+     *
      * Creates instance of an {@link Invocation} object.
      * This method is useful for framework integrators to programmatically simulate method calls on mocks using {@link MockHandler}.
      * It enables advanced framework integrations.
@@ -40,6 +46,32 @@
      * @return invocation instance
      * @since 2.10.0
      */
-    @Incubating
+    @Deprecated
     Invocation createInvocation(Object target, MockCreationSettings settings, Method method, Callable realMethod, Object... args);
+
+    /**
+     * Behavior of the real method.
+     *
+     * @since 2.14.0
+     */
+    interface RealMethodBehavior<R> extends Serializable {
+        R call() throws Throwable;
+    }
+
+    /**
+     * Creates instance of an {@link Invocation} object.
+     * This method is useful for framework integrators to programmatically simulate method calls on mocks using {@link MockHandler}.
+     * It enables advanced framework integrations.
+     *
+     * @param target the mock object the method is invoked on.
+     * @param settings creation settings of the mock object.
+     * @param method java method invoked on mock.
+     * @param realMethod real method behavior. Needed for spying / invoking real behavior on mock objects.
+     * @param args the java method arguments
+     *
+     * @return invocation instance
+     * @since 2.14.0
+     */
+    @Incubating
+    Invocation createInvocation(Object target, MockCreationSettings settings, Method method, RealMethodBehavior realMethod, Object... args);
 }
diff --git a/src/main/java/org/mockito/junit/MockitoJUnitRunner.java b/src/main/java/org/mockito/junit/MockitoJUnitRunner.java
index 2a15587..59bc92b 100644
--- a/src/main/java/org/mockito/junit/MockitoJUnitRunner.java
+++ b/src/main/java/org/mockito/junit/MockitoJUnitRunner.java
@@ -4,7 +4,6 @@
  */
 package org.mockito.junit;
 
-import java.lang.reflect.InvocationTargetException;
 import org.junit.runner.Description;
 import org.junit.runner.Runner;
 import org.junit.runner.manipulation.Filter;
@@ -16,12 +15,14 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
 import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
-import org.mockito.internal.runners.RunnerFactory;
 import org.mockito.internal.runners.InternalRunner;
+import org.mockito.internal.runners.RunnerFactory;
 import org.mockito.internal.runners.StrictRunner;
 import org.mockito.quality.MockitoHint;
 import org.mockito.quality.Strictness;
 
+import java.lang.reflect.InvocationTargetException;
+
 
 /**
  * Mockito JUnit Runner keeps tests clean and improves debugging experience.
@@ -80,6 +81,7 @@
      * stubbing argument mismatches ({@link MockitoJUnitRunner.StrictStubs})
      * and *does not detect* unused stubbings.
      * The runner remains 'silent' even if incorrect stubbing is present.
+     * It is an equivalent of {@link Strictness#LENIENT}.
      * This was the behavior of Mockito JUnit runner in versions 1.x.
      * Using this implementation of the runner is not recommended.
      * Engineers should care for removing unused stubbings because they are dead code,
diff --git a/src/main/java/org/mockito/plugins/InstantiatorProvider.java b/src/main/java/org/mockito/plugins/InstantiatorProvider.java
index b776f6e..354b87b 100644
--- a/src/main/java/org/mockito/plugins/InstantiatorProvider.java
+++ b/src/main/java/org/mockito/plugins/InstantiatorProvider.java
@@ -8,6 +8,10 @@
 import org.mockito.mock.MockCreationSettings;
 
 /**
+ * @deprecated since 2.15.4 because this internal class was leaking from the public API.
+ * For more information why deprecated, see {@link org.mockito.plugins.InstantiatorProvider2} and
+ * <a href="https://github.com/mockito/mockito/issues/1303">Issue 1303</a>
+ *
  * <p>
  *     Mockito will invoke this interface in order to fetch an instance instantiator provider.
  * </p>
@@ -44,13 +48,24 @@
  *     qualified name in the following file
  *     <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider</code>.
  * </p>
+ * <p>
+ *     This class is deprecated and was replaced by
+ *     {@link org.mockito.plugins.InstantiatorProvider2}. Hence if there is both a
+ *     <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider</code> and
+ *     <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code> the second one
+ *     takes preference.
+ * </p>
  *
- * @since 21.10.15
+ * @since 2.0.31
  */
+@Deprecated
 public interface InstantiatorProvider {
 
     /**
+     * @deprecated, see {@link InstantiatorProvider}.
+     *
      * Returns an instantiator, used to create new class instances.
      */
+    @Deprecated
     Instantiator getInstantiator(MockCreationSettings<?> settings);
 }
diff --git a/src/main/java/org/mockito/plugins/InstantiatorProvider2.java b/src/main/java/org/mockito/plugins/InstantiatorProvider2.java
new file mode 100644
index 0000000..3bc1f32
--- /dev/null
+++ b/src/main/java/org/mockito/plugins/InstantiatorProvider2.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.plugins;
+
+import org.mockito.creation.instance.Instantiator;
+import org.mockito.mock.MockCreationSettings;
+
+/**
+ * <p>
+ *     Mockito will invoke this interface in order to fetch an instance instantiator provider.
+ * </p>
+ *
+ * <p>
+ *     By default, an internal byte-buddy/asm/objenesis based implementation is used.
+ * </p>
+ *
+ * <h3>Using the extension point</h3>
+ *
+ * <p>
+ *     The plugin mechanism of mockito works in a similar way as the
+ *     {@link java.util.ServiceLoader}, however instead of looking in the <code>META-INF</code>
+ *     directory, Mockito will look in <code>mockito-extensions</code> directory.
+ *     <em>The reason for that is that Android SDK strips jar from the <code>META-INF</code>
+ *     directory when creating an APK.</em>
+ * </p>
+ *
+ * <ol style="list-style-type: lower-alpha">
+ *     <li>The implementation itself, for example
+ *         <code>org.awesome.mockito.AwesomeInstantiatorProvider2</code> that implements the
+ *         <code>InstantiatorProvider2</code>.</li>
+ *     <li>A file "<code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code>".
+ *         The content of this file is exactly a <strong>one</strong> line with the qualified
+ *         name: <code>org.awesome.mockito.AwesomeInstantiatorProvider</code>.</li>
+ * </ol></p>
+ *
+ * <p>
+ *     Note that if several <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code>
+ *     files exists in the classpath, Mockito will only use the first returned by the standard
+ *     {@link ClassLoader#getResource} mechanism.
+ * <p>
+ *     So just create a custom implementation of {@link InstantiatorProvider2} and place the
+ *     qualified name in the following file
+ *     <code>mockito-extensions/org.mockito.plugins.InstantiatorProvider2</code>.
+ * </p>
+ *
+ * @since 2.15.4
+ */
+public interface InstantiatorProvider2 {
+
+    /**
+     * Returns an instantiator, used to create new class instances.
+     *
+     * @since 2.15.4
+     */
+    Instantiator getInstantiator(MockCreationSettings<?> settings);
+}
diff --git a/src/main/java/org/mockito/quality/Strictness.java b/src/main/java/org/mockito/quality/Strictness.java
index 4e1126a..c9da8d3 100644
--- a/src/main/java/org/mockito/quality/Strictness.java
+++ b/src/main/java/org/mockito/quality/Strictness.java
@@ -80,7 +80,8 @@
      *      <li>Cleaner, more DRY tests ("Don't Repeat Yourself"):
      *          If you use {@link org.mockito.Mockito#verifyNoMoreInteractions(Object...)}
      *          you no longer need to explicitly verify stubbed invocations.
-     *          They are automatically verified for you.</li>
+     *          They are automatically verified for you. However if you have more invocations,
+     *          the test won't fail since it won't check that there are no more interactions on that stub.</li>
      *  </ul>
      *
      * For more information see {@link Strictness}.
diff --git a/src/main/java/org/mockito/session/MockitoSessionBuilder.java b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
index b13062b..474b7f9 100644
--- a/src/main/java/org/mockito/session/MockitoSessionBuilder.java
+++ b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.session;
@@ -20,7 +20,7 @@
 public interface MockitoSessionBuilder {
 
     /**
-     * Configures the test class instance for initialization of fields annotated with Mockito annotations
+     * Adds the test class instance for initialization of fields annotated with Mockito annotations
      * like {@link org.mockito.Mock}.
      * When this method is invoked it <strong>does not perform</strong> initialization of mocks on the spot!
      * Only when {@link #startMocking()} is invoked then annotated fields will be initialized.
@@ -30,11 +30,12 @@
      * Migrate from {@link MockitoAnnotations#initMocks(Object)}
      * to {@link MockitoSession}!
      * <p>
+     * This method may be called multiple times to add multiple, e.g. nested, test class instances.
+     * <p>
      * See code sample in {@link MockitoSession}.
      *
      * @param testClassInstance test class instance that contains fields with Mockito annotations to be initialized.
-     *  Passing {@code null} is permitted and will make the session use a default value.
-     *  The current default is '{@code new Object()}'.
+     *  Passing {@code null} is permitted but will be ignored.
      * @return the same builder instance for fluent configuration of {@code MockitoSession}.
      * @since 2.7.0
      */
@@ -42,6 +43,46 @@
     MockitoSessionBuilder initMocks(Object testClassInstance);
 
     /**
+     * Adds the test class instances for initialization of fields annotated with Mockito annotations
+     * like {@link org.mockito.Mock}.
+     * <p>
+     * In most scenarios, you only need to init mocks on a single test class instance.
+     * This method is useful for advanced framework integrations (like JUnit5), when a test uses multiple, e.g. nested, test class instances.
+     * <p>
+     * This method calls {@link #initMocks(Object)} for each passed test class instance.
+     *
+     * @param testClassInstances test class instances that contains fields with Mockito annotations to be initialized.
+     *  Passing {@code null} or an empty array is permitted but will be ignored.
+     * @return the same builder instance for fluent configuration of {@code MockitoSession}.
+     * @see #initMocks(Object)
+     * @since 2.15.0
+     */
+    @Incubating
+    MockitoSessionBuilder initMocks(Object... testClassInstances);
+
+    /**
+     * Configures the name of the {@code MockitoSession} instance.
+     * <p>
+     * The name is used to output {@linkplain org.mockito.quality.MockitoHint hints} when
+     * {@linkplain MockitoSession#finishMocking() finishing} a session.
+     * <p>
+     * This method is intended to be used by framework integrations, e.g. JUnit. When building
+     * a {@code MockitoSession} for direct use, users are not expected to call it.
+     *
+     * @param name of {@code MockitoSession} instance.
+     *  Passing {@code null} is permitted and will make the session use a default value.
+     *  The current default is the name of the last test class instance passed to
+     *  {@link #initMocks(Object)} or {@link #initMocks(Object...)}, if available;
+     *  otherwise, {@code "<Unnamed Session>"} is used.
+     *
+     * @return the same builder instance for fluent configuration of {@code MockitoSession}.
+     * @see org.mockito.quality.MockitoHint
+     * @since 2.15.0
+     */
+    @Incubating
+    MockitoSessionBuilder name(String name);
+
+    /**
      * Configures strictness of {@code MockitoSession} instance.
      * See examples in {@link MockitoSession}.
      *
@@ -56,6 +97,25 @@
     MockitoSessionBuilder strictness(Strictness strictness);
 
     /**
+     * Configures logger used by {@code MockitoSession} for emitting
+     * {@linkplain org.mockito.quality.MockitoHint warnings} when finishing the session.
+     * <p>
+     * Please note that the use of {@linkplain Strictness#STRICT_STUBS strict stubs} is
+     * recommended over emitting warnings because warnings are easily ignored and spoil the log output.
+     * Instead of using this method, please consider setting strictness with {@link #strictness(Strictness)}.
+     *
+     * @param logger for warnings emitted when finishing {@code MockitoSession}.
+     *  Passing {@code null} is permitted and will make the session use a default value.
+     *  By default, warnings will be logged to the console.
+     *
+     * @return the same builder instance for fluent configuration of {@code MockitoSession}.
+     * @see org.mockito.quality.MockitoHint
+     * @since 2.15.0
+     */
+    @Incubating
+    MockitoSessionBuilder logger(MockitoSessionLogger logger);
+
+    /**
      * Starts new mocking session! Creates new {@code MockitoSession} instance to initialize the session.
      * At this point annotated fields are initialized per {@link #initMocks(Object)} method.
      * When you are done with the session it is required to invoke {@link MockitoSession#finishMocking()}.
diff --git a/src/main/java/org/mockito/session/MockitoSessionLogger.java b/src/main/java/org/mockito/session/MockitoSessionLogger.java
new file mode 100644
index 0000000..e5f40ad
--- /dev/null
+++ b/src/main/java/org/mockito/session/MockitoSessionLogger.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.session;
+
+import org.mockito.Incubating;
+import org.mockito.MockitoSession;
+
+/**
+ * Logger for {@linkplain org.mockito.quality.MockitoHint hints} emitted when
+ * finishing mocking for a {@link MockitoSession}.
+ * <p>
+ * This class is intended to be used by framework integrations, e.g. JUnit. When using
+ * {@link MockitoSession} directly, you'll probably not need it.
+ *
+ * @since 2.15.0
+ */
+@Incubating
+public interface MockitoSessionLogger {
+
+    /**
+     * Logs the hint.
+     *
+     * @param hint to log; never {@code null}
+     */
+    @Incubating
+    void log(String hint);
+
+}
diff --git a/src/main/java/org/mockito/stubbing/OngoingStubbing.java b/src/main/java/org/mockito/stubbing/OngoingStubbing.java
index bc768d2..e2d298b 100644
--- a/src/main/java/org/mockito/stubbing/OngoingStubbing.java
+++ b/src/main/java/org/mockito/stubbing/OngoingStubbing.java
@@ -43,7 +43,7 @@
      *
      * @param value return value
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      */
     OngoingStubbing<T> thenReturn(T value);
 
@@ -60,7 +60,7 @@
      * @param value first return value
      * @param values next return values
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      */
     // Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation warnings (on call site)
     @SuppressWarnings ({"unchecked", "varargs"})
@@ -84,7 +84,7 @@
      *
      * @param throwables to be thrown on method invocation
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      */
     OngoingStubbing<T> thenThrow(Throwable... throwables);
 
@@ -108,7 +108,7 @@
      *
      * @param throwableType to be thrown on method invocation
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      * @since 2.1.0
      */
     OngoingStubbing<T> thenThrow(Class<? extends Throwable> throwableType);
@@ -141,7 +141,7 @@
      * @param toBeThrown to be thrown on method invocation
      * @param nextToBeThrown next to be thrown on method invocation
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      * @since 2.1.0
      */
     // Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation warnings (on call site)
@@ -175,7 +175,7 @@
      * <p>
      * See examples in javadoc for {@link Mockito#when}
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      */
     OngoingStubbing<T> thenCallRealMethod();
 
@@ -191,7 +191,7 @@
      *
      * @param answer the custom answer to execute.
      *
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      */
     OngoingStubbing<T> thenAnswer(Answer<?> answer);
 
@@ -209,7 +209,7 @@
      * </code></pre>
      *
      * @param answer the custom answer to execute.
-     * @return iOngoingStubbing object that allows stubbing consecutive calls
+     * @return object that allows stubbing consecutive calls
      *
      * @see #thenAnswer(Answer)
      * @since 1.9.0
diff --git a/src/test/java/org/mockito/InvocationFactoryTest.java b/src/test/java/org/mockito/InvocationFactoryTest.java
new file mode 100644
index 0000000..893f95f
--- /dev/null
+++ b/src/test/java/org/mockito/InvocationFactoryTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito;
+
+import org.junit.Test;
+import org.mockito.invocation.Invocation;
+import org.mockito.invocation.InvocationFactory;
+import org.mockitoutil.TestBase;
+
+import java.util.concurrent.Callable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.withSettings;
+
+public class InvocationFactoryTest extends TestBase {
+    static class TestClass {
+        public String testMethod() throws Throwable {
+            return "un-mocked";
+        }
+    }
+
+    final TestClass mock = spy(TestClass.class);
+
+    @Test
+    public void call_method_that_throws_a_throwable() throws Throwable {
+        Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock,
+            withSettings().build(TestClass.class),
+            TestClass.class.getDeclaredMethod("testMethod"),
+            new InvocationFactory.RealMethodBehavior() {
+            @Override
+            public Object call() throws Throwable {
+                throw new Throwable("mocked");
+            }
+        });
+
+        try {
+            Mockito.mockingDetails(mock).getMockHandler().handle(invocation);
+        } catch (Throwable t) {
+            assertEquals("mocked", t.getMessage());
+            return;
+        }
+
+        fail();
+    }
+
+    @Test
+    public void call_method_that_returns_a_string() throws Throwable {
+        Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock,
+            withSettings().build(TestClass.class),
+            TestClass.class.getDeclaredMethod("testMethod"),
+            new InvocationFactory.RealMethodBehavior() {
+                @Override
+                public Object call() throws Throwable {
+                    return "mocked";
+                }
+            });
+
+        Object ret = Mockito.mockingDetails(mock).getMockHandler().handle(invocation);
+        assertEquals("mocked", ret);
+    }
+
+    @Test
+    public void deprecated_api_still_works() throws Throwable {
+        Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock,
+            withSettings().build(TestClass.class),
+            TestClass.class.getDeclaredMethod("testMethod"),
+            new Callable() {
+                public Object call() throws Exception {
+                    return "mocked";
+                }
+            });
+
+        Object ret = Mockito.mockingDetails(mock).getMockHandler().handle(invocation);
+        assertEquals("mocked", ret);
+    }
+}
diff --git a/src/test/java/org/mockito/StaticMockingExperimentTest.java b/src/test/java/org/mockito/StaticMockingExperimentTest.java
index a74d5eb..bb5e225 100644
--- a/src/test/java/org/mockito/StaticMockingExperimentTest.java
+++ b/src/test/java/org/mockito/StaticMockingExperimentTest.java
@@ -10,12 +10,12 @@
 import org.mockito.exceptions.verification.WantedButNotInvoked;
 import org.mockito.exceptions.verification.junit.ArgumentsAreDifferent;
 import org.mockito.invocation.Invocation;
+import org.mockito.invocation.InvocationFactory;
 import org.mockito.invocation.MockHandler;
 import org.mockitoutil.TestBase;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
-import java.util.concurrent.Callable;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -43,9 +43,9 @@
     Foo mock = Mockito.mock(Foo.class);
     MockHandler handler = Mockito.mockingDetails(mock).getMockHandler();
     Method staticMethod;
-    Callable realMethod = new Callable() {
+    InvocationFactory.RealMethodBehavior realMethod = new InvocationFactory.RealMethodBehavior() {
         @Override
-        public Object call() throws Exception {
+        public Object call() throws Throwable {
             return null;
         }
     };
diff --git a/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java b/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java
index 41fe3cc..5935eae 100644
--- a/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java
+++ b/src/test/java/org/mockito/internal/configuration/plugins/DefaultMockitoPluginsTest.java
@@ -7,6 +7,8 @@
 import org.junit.Test;
 import org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker;
 import org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker;
+import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
 import org.mockito.plugins.MockMaker;
 import org.mockitoutil.TestBase;
 
@@ -23,5 +25,7 @@
             plugins.getDefaultPluginClass(INLINE_ALIAS));
         assertEquals(InlineByteBuddyMockMaker.class, plugins.getInlineMockMaker().getClass());
         assertEquals(ByteBuddyMockMaker.class, plugins.getDefaultPlugin(MockMaker.class).getClass());
+        assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider.class));
+        assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider2.class));
     }
 }
diff --git a/src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java b/src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java
new file mode 100644
index 0000000..ab01858
--- /dev/null
+++ b/src/test/java/org/mockito/internal/configuration/plugins/PluginLoaderTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.configuration.plugins;
+
+import org.assertj.core.api.Assertions;
+import org.assertj.core.api.ThrowableAssert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.BDDMockito.willReturn;
+import static org.mockito.Mockito.when;
+
+public class PluginLoaderTest {
+
+    @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+    @Mock PluginInitializer initializer;
+    @Mock DefaultMockitoPlugins plugins;
+    @InjectMocks PluginLoader loader;
+
+    @Test
+    public void loads_plugin() {
+        when(initializer.loadImpl(FooPlugin.class)).thenReturn(new FooPlugin());
+
+        //when
+        FooPlugin plugin = loader.loadPlugin(FooPlugin.class);
+
+        //then
+        assertNotNull(plugin);
+    }
+
+    @Test
+    public void loads_alternative_plugin() {
+        willReturn(null).given(initializer).loadImpl(FooPlugin.class);
+        BarPlugin expected = new BarPlugin();
+        willReturn(expected).given(initializer).loadImpl(BarPlugin.class);
+
+        //when
+        Object plugin = loader.loadPlugin(FooPlugin.class, BarPlugin.class);
+
+        //then
+        assertSame(plugin, expected);
+    }
+
+    @Test
+    public void loads_default_plugin() {
+        willReturn(null).given(initializer).loadImpl(FooPlugin.class);
+        willReturn(null).given(initializer).loadImpl(BarPlugin.class);
+        FooPlugin expected = new FooPlugin();
+        willReturn(expected).given(plugins).getDefaultPlugin(FooPlugin.class);
+
+        //when
+        Object plugin = loader.loadPlugin(FooPlugin.class, BarPlugin.class);
+
+        //then
+        assertSame(plugin, expected);
+    }
+
+    @Test
+    public void fails_to_load_plugin() {
+        RuntimeException cause = new RuntimeException("Boo!");
+        when(initializer.loadImpl(Foo.class)).thenThrow(cause);
+
+        //when
+        final Foo plugin = loader.loadPlugin(Foo.class);
+
+        //then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                plugin.toString(); //call any method on the plugin
+            }
+        }).isInstanceOf(IllegalStateException.class)
+            .hasMessage("Could not initialize plugin: interface org.mockito.internal.configuration.plugins.PluginLoaderTest$Foo (alternate: null)")
+            .hasCause(cause);
+    }
+
+    static class FooPlugin {}
+    static class BarPlugin {}
+    static interface Foo {}
+}
diff --git a/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java b/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java
index 50030df..320287c 100644
--- a/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java
+++ b/src/test/java/org/mockito/internal/creation/instance/ConstructorInstantiatorTest.java
@@ -65,7 +65,7 @@
         assertEquals(new ConstructorInstantiator(false, 123).newInstance(SomeClass3.class).getClass(), SomeClass3.class);
     }
 
-    @Test(expected = InstantiationException.class)
+    @Test(expected = org.mockito.creation.instance.InstantiationException.class)
     public void fails_when_null_is_passed_for_a_primitive() {
         assertEquals(new ConstructorInstantiator(false, new Object[]{null}).newInstance(SomeClass3.class).getClass(), SomeClass3.class);
     }
@@ -75,7 +75,7 @@
         try {
             new ConstructorInstantiator(false, new Object[0]).newInstance(SomeClass2.class);
             fail();
-        } catch (InstantiationException e) {
+        } catch (org.mockito.creation.instance.InstantiationException e) {
             assertThat(e).hasMessageContaining("Unable to create instance of 'SomeClass2'.\n" +
                     "Please ensure that the target class has a 0-arg constructor.");
         }
diff --git a/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java b/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java
index 696d34a..b3106a6 100644
--- a/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java
+++ b/src/test/java/org/mockito/internal/invocation/InvocationBuilder.java
@@ -6,7 +6,7 @@
 package org.mockito.internal.invocation;
 
 import org.mockito.Mockito;
-import org.mockito.internal.creation.bytebuddy.InterceptedInvocation;
+import org.mockito.internal.invocation.mockref.MockStrongReference;
 import org.mockito.internal.debugging.LocationImpl;
 import org.mockito.invocation.Invocation;
 import org.mockito.invocation.Location;
@@ -17,7 +17,7 @@
 import java.util.List;
 
 import static java.util.Arrays.asList;
-import static org.mockito.internal.creation.bytebuddy.InterceptedInvocation.NO_OP;
+import static org.mockito.internal.invocation.InterceptedInvocation.NO_OP;
 
 /**
  * Build an invocation.
@@ -61,7 +61,7 @@
             }
         }
 
-        Invocation i = new InterceptedInvocation(mock,
+        Invocation i = new InterceptedInvocation(new MockStrongReference<Object>(mock, false),
             new SerializableMethod(method),
             args,
             NO_OP,
diff --git a/src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java b/src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java
new file mode 100644
index 0000000..1e3d8e9
--- /dev/null
+++ b/src/test/java/org/mockito/internal/invocation/mockref/MockWeakReferenceTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.invocation.mockref;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.mockito.internal.invocation.mockref.MockWeakReference;
+import org.mockitoutil.TestBase;
+
+import static org.junit.Assert.fail;
+
+public class MockWeakReferenceTest extends TestBase {
+
+    @Test
+    public void descriptive_exception_when_mock_was_collected() {
+        try {
+            //when
+            new MockWeakReference(null).get();
+            //then
+            fail();
+        } catch (Exception e) {
+            Assertions.assertThat(e).hasMessageContaining("The mock object was garbage collected");
+        }
+    }
+}
diff --git a/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java b/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java
index f519186..855afb0 100644
--- a/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java
+++ b/src/test/java/org/mockito/internal/session/DefaultMockitoSessionBuilderTest.java
@@ -1,29 +1,42 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockito.internal.session;
 
 import org.junit.After;
 import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
 import org.mockito.StateMaster;
 import org.mockito.exceptions.misusing.UnfinishedMockingSessionException;
 import org.mockito.quality.Strictness;
+import org.mockito.session.MockitoSessionLogger;
 import org.mockitoutil.ThrowableAssert;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+import static org.mockito.quality.Strictness.WARN;
+
 public class DefaultMockitoSessionBuilderTest {
 
     @After public void after() {
         new StateMaster().clearMockitoListeners();
     }
 
-    @Test public void creates_sessions() throws Exception {
+    @Test public void creates_sessions() {
         //no configuration is legal
         new DefaultMockitoSessionBuilder().startMocking().finishMocking();
 
         //passing null to configuration is legal, default value will be used
-        new DefaultMockitoSessionBuilder().initMocks(null).startMocking().finishMocking();
-        new DefaultMockitoSessionBuilder().initMocks(null).strictness(null).startMocking().finishMocking();
+        new DefaultMockitoSessionBuilder().initMocks((Object) null).startMocking().finishMocking();
+        new DefaultMockitoSessionBuilder().initMocks((Object[]) null).startMocking().finishMocking();
+        new DefaultMockitoSessionBuilder().initMocks(null, null).strictness(null).startMocking().finishMocking();
         new DefaultMockitoSessionBuilder().strictness(null).startMocking().finishMocking();
 
         //happy path
@@ -32,7 +45,49 @@
         new DefaultMockitoSessionBuilder().strictness(Strictness.LENIENT).startMocking().finishMocking();
     }
 
-    @Test public void requires_finish_mocking() throws Exception {
+    @Test public void creates_sessions_for_multiple_test_class_instances_for_repeated_calls() {
+        TestClass testClass = new TestClass();
+        TestClass.NestedTestClass nestedTestClass = testClass.new NestedTestClass();
+
+        new DefaultMockitoSessionBuilder().initMocks(testClass).initMocks(nestedTestClass).startMocking().finishMocking();
+
+        assertNotNull(testClass.set);
+        assertNotNull(nestedTestClass.list);
+    }
+
+    @Test public void creates_sessions_for_multiple_test_class_instances_for_varargs_call() {
+        TestClass testClass = new TestClass();
+        TestClass.NestedTestClass nestedTestClass = testClass.new NestedTestClass();
+
+        new DefaultMockitoSessionBuilder().initMocks(testClass, nestedTestClass).startMocking().finishMocking();
+
+        assertNotNull(testClass.set);
+        assertNotNull(nestedTestClass.list);
+    }
+
+    @Test public void uses_logger_and_strictness() {
+        TestClass testClass = new TestClass();
+
+        final List<String> hints = new ArrayList<String>();
+        MockitoSession session = new DefaultMockitoSessionBuilder()
+            .initMocks(testClass)
+            .strictness(WARN)
+            .logger(new MockitoSessionLogger() {
+                @Override
+                public void log(String hint) {
+                    hints.add(hint);
+                }
+            })
+            .startMocking();
+
+        when(testClass.set.add(1)).thenReturn(true);
+
+        session.finishMocking();
+
+        assertFalse(hints.isEmpty());
+    }
+
+    @Test public void requires_finish_mocking() {
         new DefaultMockitoSessionBuilder().startMocking();
 
         ThrowableAssert.assertThat(new Runnable() {
@@ -41,4 +96,13 @@
             }
         }).throwsException(UnfinishedMockingSessionException.class);
     }
+
+    class TestClass {
+
+        @Mock public Set<Object> set;
+
+        class NestedTestClass {
+            @Mock public List<Object> list;
+        }
+    }
 }
diff --git a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
index 0e77824..de5eb13 100644
--- a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
@@ -5,8 +5,6 @@
 
 package org.mockito.internal.stubbing;
 
-import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.exceptions.base.MockitoException;
@@ -21,6 +19,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
 
 public class InvocationContainerImplStubbingTest extends TestBase {
 
@@ -96,27 +95,6 @@
     }
 
     @Test
-    public void should_add_throwable_for_void_method() throws Throwable {
-        invocationContainerImpl.addAnswerForVoidMethod(new ThrowsException(new MyException()));
-        invocationContainerImpl.setMethodForStubbing(new InvocationMatcher(simpleMethod));
-
-        try {
-            invocationContainerImpl.answerTo(simpleMethod);
-            fail();
-        } catch (MyException e) {}
-    }
-
-    @Test
-    public void should_validate_throwable_for_void_method() throws Throwable {
-        invocationContainerImpl.addAnswerForVoidMethod(new ThrowsException(new Exception()));
-
-        try {
-            invocationContainerImpl.setMethodForStubbing(new InvocationMatcher(simpleMethod));
-            fail();
-        } catch (MockitoException e) {}
-    }
-
-    @Test
     public void should_validate_throwable() throws Throwable {
         try {
             invocationContainerImpl.addAnswer(new ThrowsException(null));
diff --git a/src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java b/src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java
new file mode 100644
index 0000000..d9720f9
--- /dev/null
+++ b/src/test/java/org/mockitousage/bugs/MockitoStubbedCallInAnswerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage.bugs;
+
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.mockitoutil.TestBase;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+/**
+ * @see <a href="https://github.com/mockito/mockito/issues/1279">Issue #1279</a>
+ */
+public class MockitoStubbedCallInAnswerTest extends TestBase {
+
+    @Mock Foo foo;
+    @Mock Bar bar;
+
+    @Test
+    public void stubbing_the_right_mock() throws Exception {
+        //stubbing on different mock should not be altered
+        when(bar.doInt()).thenReturn(0);
+        when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+            @Override
+            public Integer answer(InvocationOnMock invocation) throws Throwable {
+                return bar.doInt();
+            }
+        });
+        assertEquals(0, foo.doInt());
+        assertEquals(0, bar.doInt());
+
+        //when we override the stubbing
+        when(foo.doInt()).thenReturn(1);
+
+        //we expect it to be reflected:
+        assertEquals(1, foo.doInt());
+
+        //but the stubbing on a different mock should not be altered:
+        assertEquals(0, bar.doInt());
+    }
+
+    @Test
+    public void return_type_validation() throws Exception {
+        when(foo.doString()).thenAnswer(new Answer<String>() {
+            public String answer(InvocationOnMock invocation) throws Throwable {
+                //invoking a method on a different mock, with different return type
+                return String.valueOf(bar.doInt());
+            }
+        });
+        assertEquals("0", foo.doString());
+
+        //we can override stubbing without misleading return type validation errors:
+        when(foo.doString()).thenReturn("");
+        assertEquals("", foo.doString());
+    }
+
+    @Test
+    public void prevents_stack_overflow() throws Exception {
+        when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+            public Integer answer(InvocationOnMock invocation) throws Throwable {
+                return bar.doInt();
+            }
+        });
+        assertEquals(0, foo.doInt());
+
+        when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+            public Integer answer(InvocationOnMock invocation) throws Throwable {
+                return bar.doInt() + 1;
+            }
+        });
+
+        //calling below used to cause SO error
+        assertEquals(1, foo.doInt());
+    }
+
+    @Test
+    public void overriding_stubbing() throws Exception {
+        when(bar.doInt()).thenReturn(10);
+        when(foo.doInt()).thenAnswer(new Answer<Integer>() {
+            public Integer answer(InvocationOnMock invocation) throws Throwable {
+                return bar.doInt() + 1;
+            }
+        });
+
+        assertEquals(11, foo.doInt());
+
+        //when we override the stubbing with a different one
+        when(foo.doInt()).thenReturn(100);
+
+        //we expect it to be reflected:
+        assertEquals(100, foo.doInt());
+    }
+
+    interface Foo {
+        String doString();
+        int doInt();
+    }
+
+    interface Bar {
+        int doInt();
+    }
+}
diff --git a/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java b/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
index 59e5999..f4e3e95 100644
--- a/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
+++ b/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
@@ -8,18 +8,20 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
-import org.mockito.quality.Strictness;
 import org.mockito.exceptions.misusing.PotentialStubbingProblem;
 import org.mockito.exceptions.misusing.UnfinishedVerificationException;
 import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
 import org.mockito.junit.MockitoJUnit;
+import org.mockito.quality.Strictness;
 import org.mockitousage.IMethods;
 import org.mockitoutil.SafeJUnitRule;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.BDDMockito.willReturn;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 import static org.mockitoutil.TestBase.filterLineNo;
 
 public class StrictJUnitRuleTest {
@@ -97,7 +99,7 @@
                                 "  - stubbing the same method multiple times using 'given().will()' or 'when().then()' API\n" +
                                 "    Please use 'will().given()' or 'doReturn().when()' API for stubbing.\n" +
                                 "  - stubbed method is intentionally invoked with different arguments by code under test\n" +
-                                "    Please use 'default' or 'silent' JUnit Rule.\n" +
+                                "    Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).\n" +
                                 "For more information see javadoc for PotentialStubbingProblem class."),
                         filterLineNo(t.getMessage()));
             }
@@ -140,7 +142,7 @@
                         "Following stubbings are unnecessary (click to navigate to relevant line of code):\n" +
                         "  1. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
                         "  2. -> at org.mockitousage.junitrule.StrictJUnitRuleTest.unused_stubs_with_multiple_mocks(StrictJUnitRuleTest.java:0)\n" +
-                        "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class."), filterLineNo(t.getMessage()));
+                        "Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class."), filterLineNo(t.getMessage()));
             }
         });
 
diff --git a/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java b/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java
index 0d8cead..6b6017a 100644
--- a/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java
+++ b/src/test/java/org/mockitousage/junitrunner/UnusedStubsExceptionMessageTest.java
@@ -53,7 +53,7 @@
                         "Following stubbings are unnecessary (click to navigate to relevant line of code):\n" +
                         "  1. -> at org.mockitousage.junitrunner.UnusedStubsExceptionMessageTest$HasUnnecessaryStubs.<init>(UnusedStubsExceptionMessageTest.java:0)\n" +
                         "  2. -> at org.mockitousage.junitrunner.UnusedStubsExceptionMessageTest$HasUnnecessaryStubs.<init>(UnusedStubsExceptionMessageTest.java:0)\n" +
-                        "Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.",
-                filterLineNo(failure.getException().getMessage()));
+                        "Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.",
+            filterLineNo(failure.getException().getMessage()));
     }
 }
diff --git a/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java b/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java
index 0d164c6..a1a3500 100644
--- a/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java
+++ b/src/test/java/org/mockitousage/plugins/MockitoPluginsTest.java
@@ -6,8 +6,10 @@
 
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.mockito.internal.creation.instance.Instantiator;
 import org.mockito.plugins.AnnotationEngine;
 import org.mockito.plugins.InstantiatorProvider;
+import org.mockito.plugins.InstantiatorProvider2;
 import org.mockito.plugins.MockMaker;
 import org.mockito.plugins.MockitoPlugins;
 import org.mockito.plugins.PluginSwitch;
@@ -15,17 +17,29 @@
 import org.mockitoutil.TestBase;
 
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.withSettings;
 
 public class MockitoPluginsTest extends TestBase {
 
     private final MockitoPlugins plugins = Mockito.framework().getPlugins();
 
-    @Test public void provides_built_in_plugins() {
+    @Test
+    public void provides_built_in_plugins() {
         assertNotNull(plugins.getInlineMockMaker());
         assertNotNull(plugins.getDefaultPlugin(MockMaker.class));
         assertNotNull(plugins.getDefaultPlugin(StackTraceCleanerProvider.class));
         assertNotNull(plugins.getDefaultPlugin(PluginSwitch.class));
         assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider.class));
+        assertNotNull(plugins.getDefaultPlugin(InstantiatorProvider2.class));
         assertNotNull(plugins.getDefaultPlugin(AnnotationEngine.class));
     }
+
+    @SuppressWarnings("deprecation")
+    @Test
+    public void instantiator_provider_backwards_compatibility() {
+        InstantiatorProvider provider = plugins.getDefaultPlugin(InstantiatorProvider.class);
+        Instantiator instantiator = provider.getInstantiator(withSettings().build(MockitoPluginsTest.class));
+
+        assertNotNull(instantiator.newInstance(MockitoPluginsTest.class));
+    }
 }
diff --git a/src/test/java/org/mockitousage/session/MockitoSessionTest.java b/src/test/java/org/mockitousage/session/MockitoSessionTest.java
index e992f83..960d888 100644
--- a/src/test/java/org/mockitousage/session/MockitoSessionTest.java
+++ b/src/test/java/org/mockitousage/session/MockitoSessionTest.java
@@ -15,13 +15,17 @@
 import org.mockito.quality.Strictness;
 import org.mockitousage.IMethods;
 import org.mockitoutil.JUnitResultAssert;
+import org.mockitoutil.TestBase;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mockingDetails;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-public class MockitoSessionTest {
+public class MockitoSessionTest extends TestBase {
 
     private JUnitCore junit = new JUnitCore();
 
@@ -66,6 +70,33 @@
                 .failsExactly(AssertionError.class, UnfinishedStubbingException.class);
     }
 
+    @Test public void allows_initializing_mocks_manually() {
+        //when
+        Result result = junit.run(MockitoSessionTest.SessionWithManuallyInitializedMock.class);
+
+        //expect
+        JUnitResultAssert.assertThat(result).succeeds(1);
+    }
+
+    @Test public void allows_updating_strictness() {
+        //when
+        Result result = junit.run(MockitoSessionTest.SessionWithUpdatedStrictness.class);
+
+        //expect
+        JUnitResultAssert.assertThat(result).succeeds(1);
+    }
+
+    @Test public void allows_overriding_failure() {
+        //when
+        Result result = junit.run(MockitoSessionTest.SessionWithOverriddenFailure.class);
+
+        //expect
+        JUnitResultAssert.assertThat(result).isSuccessful();
+
+        //in order to demonstrate feature, we intentionally misuse Mockito and need to clean up state
+        resetState();
+    }
+
     public static class SessionWithoutAnyConfiguration {
 
         @Mock IMethods mock;
@@ -139,4 +170,52 @@
             assertTrue(false);
         }
     }
+
+    public static class SessionWithManuallyInitializedMock {
+        @Mock IMethods mock;
+        IMethods mock2 = Mockito.mock(IMethods.class, "manual mock");
+
+        MockitoSession mockito = Mockito.mockitoSession().initMocks(this).startMocking();
+
+        @After public void after() {
+            mockito.finishMocking();
+        }
+
+        @Test public void manual_mock_preserves_its_settings() {
+            assertEquals("mock", mockingDetails(mock).getMockCreationSettings().getMockName().toString());
+            assertEquals("manual mock", mockingDetails(mock2).getMockCreationSettings().getMockName().toString());
+        }
+    }
+
+    public static class SessionWithUpdatedStrictness {
+        @Mock IMethods mock;
+        MockitoSession mockito = Mockito.mockitoSession().initMocks(this).strictness(Strictness.STRICT_STUBS).startMocking();
+
+        @After public void after() {
+            mockito.finishMocking();
+        }
+
+        @Test public void manual_mock_preserves_its_settings() {
+            when(mock.simpleMethod(1)).thenReturn("foo");
+
+            //when
+            mockito.setStrictness(Strictness.LENIENT);
+
+            //then no exception is thrown, even though the arg is different
+            mock.simpleMethod(2);
+        }
+    }
+
+    public static class SessionWithOverriddenFailure {
+        @Mock IMethods mock;
+        MockitoSession mockito = Mockito.mockitoSession().initMocks(this).startMocking();
+
+        @After public void after() {
+            mockito.finishMocking(new RuntimeException("Boo!"));
+        }
+
+        @Test public void invalid_mockito_usage() {
+            verify(mock);
+        }
+    }
 }
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
index 74acd78..754b7dc 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
@@ -1,27 +1,40 @@
 /*
- * Copyright (c) 2017 Mockito contributors
+ * Copyright (c) 2018 Mockito contributors
  * This program is made available under the terms of the MIT License.
  */
 package org.mockitousage.stubbing;
 
+import org.junit.After;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoSession;
+import org.mockito.StateMaster;
+import org.mockito.exceptions.base.MockitoException;
 import org.mockito.internal.framework.DefaultMockitoSession;
 import org.mockito.internal.util.SimpleMockitoLogger;
 import org.mockito.quality.Strictness;
 import org.mockitousage.IMethods;
 
+import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.verify;
 import static org.mockitoutil.TestBase.filterLineNo;
 
 public class StubbingWarningsTest {
 
+    private static final String TEST_NAME = "test.name";
+
     @Mock IMethods mock;
 
     SimpleMockitoLogger logger = new SimpleMockitoLogger();
-    MockitoSession mockito = new DefaultMockitoSession(this, Strictness.WARN, logger);
+    MockitoSession mockito = new DefaultMockitoSession(singletonList((Object) this), TEST_NAME, Strictness.WARN, logger);
+
+    @After public void after() {
+        StateMaster stateMaster = new StateMaster();
+        stateMaster.reset();
+        stateMaster.clearMockitoListeners();
+    }
 
     @Test public void few_interactions() throws Throwable {
         //when
@@ -65,7 +78,7 @@
         //because it was simpler to implement. This can be improved given we put priority to improve the warnings.
         //then
         assertEquals(filterLineNo(
-            "[MockitoHint] StubbingWarningsTest.null (see javadoc for MockitoHint):\n" +
+            "[MockitoHint] " + TEST_NAME + " (see javadoc for MockitoHint):\n" +
             "[MockitoHint] 1. Unused -> at org.mockitousage.stubbing.StubbingWarningsTest.stubbing_argument_mismatch(StubbingWarningsTest.java:0)\n"),
                 filterLineNo(logger.getLoggedInfo()));
     }
@@ -78,8 +91,25 @@
 
         //then
         assertEquals(filterLineNo(
-            "[MockitoHint] StubbingWarningsTest.null (see javadoc for MockitoHint):\n" +
+            "[MockitoHint] " + TEST_NAME + " (see javadoc for MockitoHint):\n" +
             "[MockitoHint] 1. Unused -> at org.mockitousage.stubbing.StubbingWarningsTest.unused_stubbing(StubbingWarningsTest.java:0)\n"),
                 filterLineNo(logger.getLoggedInfo()));
     }
+
+    @Test(expected = MockitoException.class) public void unfinished_verification_without_throwable() throws Throwable {
+        //when
+        verify(mock);
+
+        mockito.finishMocking();
+    }
+
+    @Test public void unfinished_verification_with_throwable() throws Throwable {
+        //when
+        verify(mock);
+
+        mockito.finishMocking(new AssertionError());
+
+        // then
+        logger.assertEmpty();
+    }
 }
diff --git a/src/test/java/org/mockitoutil/TestBase.java b/src/test/java/org/mockitoutil/TestBase.java
index 2971ee5..ca3d7b8 100644
--- a/src/test/java/org/mockitoutil/TestBase.java
+++ b/src/test/java/org/mockitoutil/TestBase.java
@@ -11,7 +11,8 @@
 import org.mockito.StateMaster;
 import org.mockito.internal.MockitoCore;
 import org.mockito.internal.configuration.ConfigurationAccess;
-import org.mockito.internal.creation.bytebuddy.InterceptedInvocation;
+import org.mockito.internal.invocation.mockref.MockStrongReference;
+import org.mockito.internal.invocation.InterceptedInvocation;
 import org.mockito.internal.debugging.LocationImpl;
 import org.mockito.internal.invocation.InvocationBuilder;
 import org.mockito.internal.invocation.InvocationMatcher;
@@ -64,8 +65,9 @@
         for (int i = 0; i < args.length; i++) {
             types[i] = args[i].getClass();
         }
-        return new InterceptedInvocation(mock(type), new SerializableMethod(type.getMethod(methodName,
-                types)), args, InterceptedInvocation.NO_OP, new LocationImpl(), 1);
+        return new InterceptedInvocation(new MockStrongReference<Object>(mock(type), false),
+            new SerializableMethod(type.getMethod(methodName, types)), args, InterceptedInvocation.NO_OP,
+            new LocationImpl(), 1);
     }
 
     protected static Invocation invocationAt(String location) {
diff --git a/stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java b/stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
deleted file mode 100644
index c9b8a7c..0000000
--- a/stub/java/org/mockito/internal/invocation/DefaultInvocationFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.mockito.internal.invocation;
-
-import org.mockito.invocation.Invocation;
-import org.mockito.invocation.InvocationFactory;
-import org.mockito.mock.MockCreationSettings;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.Callable;
-
-public class DefaultInvocationFactory implements InvocationFactory {
-
-    public Invocation createInvocation(Object target, MockCreationSettings settings, Method method, Callable realMethod, Object... args) {
-        throw new RuntimeException("Not implemented");
-    }
-}
diff --git a/subprojects/inline/inline.gradle b/subprojects/inline/inline.gradle
index be10361..b8d2577 100644
--- a/subprojects/inline/inline.gradle
+++ b/subprojects/inline/inline.gradle
@@ -8,3 +8,6 @@
 }
 
 tasks.javadoc.enabled = false
+
+//required by the "StressTest.java"
+test.maxHeapSize = "256m"
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java b/subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java
new file mode 100644
index 0000000..2a4494e
--- /dev/null
+++ b/subprojects/inline/src/test/java/org/mockitoinline/RecursionTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoinline;
+
+import org.junit.Test;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.mockito.Mockito.spy;
+
+public class RecursionTest {
+
+    @Test
+    public void testMockConcurrentHashMap() {
+        ConcurrentMap<String, String> map = spy(new ConcurrentHashMap<String, String>());
+        map.putIfAbsent("a", "b");
+    }
+}
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/StressTest.java b/subprojects/inline/src/test/java/org/mockitoinline/StressTest.java
new file mode 100644
index 0000000..c6a5506
--- /dev/null
+++ b/subprojects/inline/src/test/java/org/mockitoinline/StressTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoinline;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+public class StressTest {
+    public class TestClass {
+        public String getStuff() {
+            return "A";
+        }
+    }
+
+    @Test
+    public void call_a_lot_of_mocks() {
+        //This requires smaller heap set for the test process, see "inline.gradle"
+        for (int i = 0; i < 40000; i++) {
+            TestClass mock = mock(TestClass.class);
+            when(mock.getStuff()).thenReturn("B");
+            assertEquals("B", mock.getStuff());
+
+            TestClass serializableMock = mock(TestClass.class, withSettings().serializable());
+            when(serializableMock.getStuff()).thenReturn("C");
+            assertEquals("C", serializableMock.getStuff());
+
+            if (i % 1024 == 0) {
+                System.out.println(i + "/40000 mocks called");
+            }
+        }
+    }
+}
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java b/subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java
new file mode 100644
index 0000000..1fe8196
--- /dev/null
+++ b/subprojects/inline/src/test/java/org/mockitoinline/SuperCallTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoinline;
+
+import org.junit.Test;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+public final class SuperCallTest {
+
+    @Test
+    public void testSuperMethodCall() {
+        Dummy d = spy(new Dummy());
+        d.foo();
+        verify(d).bar(eq("baz"));
+    }
+
+    static class Dummy {
+
+        public void foo() {
+            bar("baz");
+        }
+
+        // Also fails if public.
+        void bar(String s) {
+            return;
+        }
+    }
+}