summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJon Boekenoogen <jboekeno@google.com>2014-06-02 18:56:43 -0700
committerJon Boekenoogen <jboekeno@google.com>2014-06-12 09:01:05 -0700
commit674060f01e9090cd21b3c5656cc3204912ad17a6 (patch)
treee009607bd55be60cff6bdd1e0e17535ea00b5394 /src
parent6c4e9659e02223565e17c32063e24c6907795687 (diff)
downloadmockito-674060f01e9090cd21b3c5656cc3204912ad17a6.tar.gz
Update to support host use of mockito.
1) Download source necessary for host use. Sync'ed at the same CL 635c5f8353b0e49c4d3f2c71cc250a681c2e4cd6 the repo was currently at. 2) Remove host source from the target build. Should have no impact on pre-existing projects. 3) Get build.gradle working for target only. Will update to fix the host build later since it will require lots of dependent CLs. Change-Id: I31d49f422af2d5910cfd7acf86d6627ee3ee7fc2
Diffstat (limited to 'src')
-rw-r--r--src/org/mockito/internal/creation/AbstractMockitoMethodProxy.java12
-rw-r--r--src/org/mockito/internal/creation/AcrossJVMSerializationFeature.java416
-rw-r--r--src/org/mockito/internal/creation/CglibMockMaker.java51
-rw-r--r--src/org/mockito/internal/creation/DelegatingMockitoMethodProxy.java20
-rw-r--r--src/org/mockito/internal/creation/MethodInterceptorFilter.java85
-rw-r--r--src/org/mockito/internal/creation/MockitoMethodProxy.java15
-rw-r--r--src/org/mockito/internal/creation/SerializableMockitoMethodProxy.java37
-rw-r--r--src/org/mockito/internal/creation/cglib/CGLIBHacker.java46
-rw-r--r--src/org/mockito/internal/creation/cglib/MockitoNamingPolicy.java17
-rw-r--r--src/org/mockito/internal/creation/cglib/package.html6
-rw-r--r--src/org/mockito/internal/creation/jmock/ClassImposterizer.java148
-rw-r--r--src/org/mockito/internal/creation/jmock/SearchingClassLoader.java76
-rw-r--r--src/org/mockito/internal/creation/jmock/SerializableNoOp.java20
-rw-r--r--src/org/mockito/internal/creation/jmock/jmock-license.txt25
-rw-r--r--src/org/mockito/internal/creation/jmock/package.html6
-rw-r--r--src/org/mockito/internal/invocation/realmethod/CGLIBProxyRealMethod.java28
-rw-r--r--src/org/mockito/internal/invocation/realmethod/FilteredCGLIBProxyRealMethod.java37
-rw-r--r--src/org/mockito/internal/invocation/realmethod/HasCGLIBMethodProxy.java14
18 files changed, 1059 insertions, 0 deletions
diff --git a/src/org/mockito/internal/creation/AbstractMockitoMethodProxy.java b/src/org/mockito/internal/creation/AbstractMockitoMethodProxy.java
new file mode 100644
index 0000000..a6b6bb0
--- /dev/null
+++ b/src/org/mockito/internal/creation/AbstractMockitoMethodProxy.java
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation;
+
+public abstract class AbstractMockitoMethodProxy implements MockitoMethodProxy {
+
+ public Object invokeSuper(Object target, Object[] arguments) throws Throwable {
+ return getMethodProxy().invokeSuper(target, arguments);
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/AcrossJVMSerializationFeature.java b/src/org/mockito/internal/creation/AcrossJVMSerializationFeature.java
new file mode 100644
index 0000000..94f6b6f
--- /dev/null
+++ b/src/org/mockito/internal/creation/AcrossJVMSerializationFeature.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.creation;
+
+import org.mockito.Incubating;
+import org.mockito.exceptions.base.MockitoSerializationIssue;
+import org.mockito.internal.creation.jmock.ClassImposterizer;
+import org.mockito.internal.util.MockUtil;
+import org.mockito.internal.util.reflection.FieldSetter;
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.mock.MockName;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static org.mockito.internal.util.StringJoiner.join;
+
+/**
+ * This is responsible for serializing a mock, it is enabled if the mock is implementing
+ * {@link Serializable}.
+ *
+ * <p>
+ * The way it works is to enable serialization via the {@link #enableSerializationAcrossJVM(MockCreationSettings)},
+ * if the mock settings is set to be serializable it will add the {@link org.mockito.internal.creation.AcrossJVMSerializationFeature.AcrossJVMMockitoMockSerializable} interface.
+ * This interface defines a the {@link org.mockito.internal.creation.AcrossJVMSerializationFeature.AcrossJVMMockitoMockSerializable#writeReplace()}
+ * whose signature match the one that is looked by the standard Java serialization.
+ * </p>
+ *
+ * <p>
+ * Then in the {@link MethodInterceptorFilter} of mockito, if the <code>writeReplace</code> method is called,
+ * it will use the custom implementation of this class {@link #writeReplace(Object)}. This method has a specific
+ * knowledge on how to serialize a mockito mock that is based on CGLIB.
+ * </p>
+ *
+ * <p><strong>Only one instance per mock! See {@link MethodInterceptorFilter}</strong></p>
+ *
+ * TODO use a proper way to add the interface
+ * TODO offer a way to disable completely this behavior, or maybe enable this behavior only with a specific setting
+ * TODO check the class is mockable in the deserialization side
+ *
+ * @see CglibMockMaker
+ * @see MethodInterceptorFilter
+ * @author Brice Dutheil
+ * @since 1.9.6
+ */
+@Incubating
+public class AcrossJVMSerializationFeature implements Serializable {
+ private static final long serialVersionUID = 7411152578314420778L;
+ private static final String MOCKITO_PROXY_MARKER = "MockitoProxyMarker";
+ private boolean instanceLocalCurrentlySerializingFlag = false;
+ private Lock mutex = new ReentrantLock();
+
+ public boolean isWriteReplace(Method method) {
+ return method.getReturnType() == Object.class
+ && method.getParameterTypes().length == 0
+ && method.getName().equals("writeReplace");
+ }
+
+
+ /**
+ * Custom implementation of the <code>writeReplace</code> method for serialization.
+ *
+ * Here's how it's working and why :
+ * <ol>
+ * <li>
+ * <p>When first entering in this method, it's because some is serializing the mock, with some code like :
+ * <pre class="code"><code class="java">
+ * objectOutputStream.writeObject(mock);
+ * </code></pre>
+ * So, {@link ObjectOutputStream} will track the <code>writeReplace</code> method in the instance and
+ * execute it, which is wanted to replace the mock by another type that will encapsulate the actual mock.
+ * At this point, the code will return an {@link AcrossJVMMockSerializationProxy}.</p>
+ * </li>
+ * <li>
+ * <p>Now, in the constructor {@link AcrossJVMMockSerializationProxy#AcrossJVMMockSerializationProxy(Object)}
+ * the mock is being serialized in a custom way (using {@link MockitoMockObjectOutputStream}) to a
+ * byte array. So basically it means the code is performing double nested serialization of the passed
+ * <code>mockitoMock</code>.</p>
+ *
+ * <p>However the <code>ObjectOutputStream</code> will still detect the custom
+ * <code>writeReplace</code> and execute it.
+ * <em>(For that matter disabling replacement via {@link ObjectOutputStream#enableReplaceObject(boolean)}
+ * doesn't disable the <code>writeReplace</code> call, but just just toggle replacement in the
+ * written stream, <strong><code>writeReplace</code> is always called by
+ * <code>ObjectOutputStream</code></strong>.)</em></p>
+ *
+ * <p>In order to avoid this recursion, obviously leading to a {@link StackOverflowError}, this method is using
+ * a flag that marks the mock as already being replaced, and then shouldn't replace itself again.
+ * <strong>This flag is local to this class</strong>, which means the flag of this class unfortunately needs
+ * to be protected against concurrent access, hence the reentrant lock.</p>
+ * </li>
+ * </ol>
+ *
+ *
+ * @param mockitoMock The Mockito mock to be serialized.
+ * @return A wrapper ({@link AcrossJVMMockSerializationProxy}) to be serialized by the calling ObjectOutputStream.
+ * @throws ObjectStreamException
+ */
+ public Object writeReplace(Object mockitoMock) throws ObjectStreamException {
+ try {
+ // reentrant lock for critical section. could it be improved ?
+ mutex.lock();
+ // mark started flag // per thread, not per instance
+ // temporary loosy hack to avoid stackoverflow
+ if(mockIsCurrentlyBeingReplaced()) {
+ return mockitoMock;
+ }
+ mockReplacementStarted();
+
+ return new AcrossJVMMockSerializationProxy(mockitoMock);
+ } catch (IOException ioe) {
+ MockUtil mockUtil = new MockUtil();
+ MockName mockName = mockUtil.getMockName(mockitoMock);
+ String mockedType = mockUtil.getMockSettings(mockitoMock).getTypeToMock().getCanonicalName();
+ throw new MockitoSerializationIssue(join(
+ "The mock '" + mockName + "' of type '" + mockedType + "'",
+ "The Java Standard Serialization reported an '" + ioe.getClass().getSimpleName() + "' saying :",
+ " " + ioe.getMessage()
+ ), ioe);
+ } finally {
+ // unmark
+ mockReplacementCompleted();
+ mutex.unlock();
+ }
+ }
+
+
+ private void mockReplacementCompleted() {
+ instanceLocalCurrentlySerializingFlag = false;
+ }
+
+
+ private void mockReplacementStarted() {
+ instanceLocalCurrentlySerializingFlag = true;
+ }
+
+
+ private boolean mockIsCurrentlyBeingReplaced() {
+ return instanceLocalCurrentlySerializingFlag;
+ }
+
+
+ /**
+ * Enable serialization serialization that will work across classloaders / and JVM.
+ *
+ * <p>Only enable if settings says the mock should be serializable. In this case add the
+ * {@link AcrossJVMMockitoMockSerializable} to the extra interface list.</p>
+ *
+ * @param settings Mock creation settings.
+ * @param <T> Type param to not be bothered by the generics
+ */
+ public <T> void enableSerializationAcrossJVM(MockCreationSettings<T> settings) {
+ if (settings.isSerializable()) {
+ // havin faith that this set is modifiable
+ // TODO use a proper way to add the interface
+ settings.getExtraInterfaces().add(AcrossJVMMockitoMockSerializable.class);
+ }
+ }
+
+
+ /**
+ * This is the serialization proxy that will encapsulate the real mock data as a byte array.
+ *
+ * <p>When called in the constructor it will serialize the mock in a byte array using a
+ * custom {@link MockitoMockObjectOutputStream} that will annotate the mock class in the stream.
+ * other information are used in this class in order to facilitate deserialization.
+ * </p>
+ *
+ * <p>Deserialization of the mock will be performed by the {@link #readResolve()} method via
+ * the custom {@link MockitoMockObjectInputStream} that will be in charge of creating the mock class.</p>
+ */
+ public static class AcrossJVMMockSerializationProxy implements Serializable {
+
+
+ private static final long serialVersionUID = -7600267929109286514L;
+ private byte[] serializedMock;
+ private Class typeToMock;
+ private Set<Class> extraInterfaces;
+ /**
+ * Creates the wrapper that be used in the serialization stream.
+ *
+ * <p>Immediately serializes the Mockito mock using specifically crafted {@link MockitoMockObjectOutputStream},
+ * in a byte array.</p>
+ *
+ * @param mockitoMock The Mockito mock to serialize.
+ * @throws IOException
+ */
+ public AcrossJVMMockSerializationProxy(Object mockitoMock) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ObjectOutputStream objectOutputStream = new MockitoMockObjectOutputStream(out);
+
+ objectOutputStream.writeObject(mockitoMock);
+
+ objectOutputStream.close();
+ out.close();
+
+ MockCreationSettings mockSettings = new MockUtil().getMockSettings(mockitoMock);
+ this.serializedMock = out.toByteArray();
+ this.typeToMock = mockSettings.getTypeToMock();
+ this.extraInterfaces = mockSettings.getExtraInterfaces();
+ }
+
+ /**
+ * Resolves the proxy to a new deserialized instance of the Mockito mock.
+ *
+ * <p>Uses the custom crafted {@link MockitoMockObjectInputStream} to deserialize the mock.</p>
+ *
+ * @return A deserialized instance of the Mockito mock.
+ * @throws ObjectStreamException
+ */
+ private Object readResolve() throws ObjectStreamException {
+ try {
+ ByteArrayInputStream bis = new ByteArrayInputStream(serializedMock);
+ ObjectInputStream objectInputStream = new MockitoMockObjectInputStream(bis, typeToMock, extraInterfaces);
+
+ Object deserializedMock = objectInputStream.readObject();
+
+ bis.close();
+ objectInputStream.close();
+
+ return deserializedMock;
+ } catch (IOException ioe) {
+ throw new MockitoSerializationIssue(join(
+ "Mockito mock cannot be deserialized to a mock of '" + typeToMock.getCanonicalName() + "'. The error was :",
+ " " + ioe.getMessage(),
+ "If you are unsure what is the reason of this exception, feel free to contact us on the mailing list."
+ ), ioe);
+ } catch (ClassNotFoundException cce) {
+ throw new MockitoSerializationIssue(join(
+ "A class couldn't be found while deserializing a Mockito mock, you should check your classpath. The error was :",
+ " " + cce.getMessage(),
+ "If you are still unsure what is the reason of this exception, feel free to contact us on the mailing list."
+ ), cce);
+ }
+ }
+ }
+
+
+ /**
+ * Special Mockito aware <code>ObjectInputStream</code> that will resolve the Mockito proxy class.
+ *
+ * <p>
+ * This specificaly crafted ObjectInoutStream has the most important role to resolve the Mockito generated
+ * class. It is doing so via the {@link #resolveClass(java.io.ObjectStreamClass)} which looks in the stream
+ * for a Mockito marker. If this marker is found it will try to resolve the mockito class otherwise it
+ * delegates class resolution to the default super behavior.
+ * The mirror method used for serializing the mock is {@link MockitoMockObjectOutputStream#annotateClass(Class)}.
+ * </p>
+ *
+ * <p>
+ * When this marker is found, {@link ClassImposterizer} methods are being used to create the mock class.
+ * <em>Note that behind the <code>ClassImposterizer</code> there is CGLIB and the
+ * {@link org.mockito.internal.creation.jmock.SearchingClassLoader} that will look if this enhanced class has
+ * already been created in an accessible classloader ; so basically this code trusts the ClassImposterizer
+ * code.</em>
+ * </p>
+ */
+ public static class MockitoMockObjectInputStream extends ObjectInputStream {
+ private Class typeToMock;
+ private Set<Class> extraInterfaces;
+
+ public MockitoMockObjectInputStream(InputStream in, Class typeToMock, Set<Class> extraInterfaces) throws IOException {
+ super(in) ;
+ this.typeToMock = typeToMock;
+ this.extraInterfaces = extraInterfaces;
+ enableResolveObject(true); // ensure resolving is enabled
+ }
+
+ /**
+ * Resolve the Mockito proxy class if it is marked as such.
+ *
+ * <p>Uses the fields {@link #typeToMock} and {@link #extraInterfaces} to
+ * create the Mockito proxy class as the <code>ObjectStreamClass</code>
+ * doesn't carry useful information for this purpose.</p>
+ *
+ * @param desc Description of the class in the stream, not used.
+ * @return The class that will be used to deserialize the instance mock.
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+ if (notMarkedAsAMockitoMock(readObject())) {
+ return super.resolveClass(desc);
+ }
+
+ // TODO check the class is mockable in the deserialization side
+ // ClassImposterizer.INSTANCE.canImposterise(typeToMock);
+
+ // create the Mockito mock class before it can even be deserialized
+ ClassImposterizer.INSTANCE.setConstructorsAccessible(typeToMock, true);
+ Class<?> proxyClass = ClassImposterizer.INSTANCE.createProxyClass(
+ typeToMock,
+ extraInterfaces.toArray(new Class[extraInterfaces.size()])
+ );
+
+ hackClassNameToMatchNewlyCreatedClass(desc, proxyClass);
+
+ return proxyClass;
+
+ }
+
+ /**
+ * Hack the <code>name</code> field of the given <code>ObjectStreamClass</code> with
+ * the <code>newProxyClass</code>.
+ *
+ * The parent ObjectInputStream will check the name of the class in the stream matches the name of the one
+ * that is created in this method.
+ *
+ * The CGLIB classes uses a hash of the classloader and/or maybe some other data that allow them to be
+ * relatively unique in a JVM.
+ *
+ * When names differ, which happens when the mock is deserialized in another ClassLoader, a
+ * <code>java.io.InvalidObjectException</code> is thrown, so this part of the code is hacking through
+ * the given <code>ObjectStreamClass</code> to change the name with the newly created class.
+ *
+ * @param descInstance The <code>ObjectStreamClass</code> that will be hacked.
+ * @param proxyClass The proxy class whose name will be applied.
+ * @throws InvalidObjectException
+ */
+ private void hackClassNameToMatchNewlyCreatedClass(ObjectStreamClass descInstance, Class<?> proxyClass) throws ObjectStreamException {
+ try {
+ Field classNameField = descInstance.getClass().getDeclaredField("name");
+ new FieldSetter(descInstance, classNameField).set(proxyClass.getCanonicalName());
+ } catch (NoSuchFieldException nsfe) {
+ // TODO use our own mockito mock serialization exception
+ throw new MockitoSerializationIssue(join(
+ "Wow, the class 'ObjectStreamClass' in the JDK don't have the field 'name',",
+ "this is definitely a bug in our code as it means the JDK team changed a few internal things.",
+ "",
+ "Please report an issue with the JDK used, a code sample and a link to download the JDK would be welcome."
+ ), nsfe);
+ }
+ }
+
+ /**
+ * Read the stream class annotation and identify it as a Mockito mock or not.
+ *
+ * @param marker The marker to identify.
+ * @return <code>true</code> if not marked as a Mockito, <code>false</code> if the class annotation marks a Mockito mock.
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ private boolean notMarkedAsAMockitoMock(Object marker) throws IOException, ClassNotFoundException {
+ return !MOCKITO_PROXY_MARKER.equals(marker);
+ }
+ }
+
+
+ /**
+ * Special Mockito aware <code>ObjectOutputStream</code>.
+ *
+ * <p>
+ * This output stream has the role of marking in the stream the Mockito class. This
+ * marking process is necessary to identify the proxy class that will need to be recreated.
+ *
+ * The mirror method used for deserializing the mock is
+ * {@link MockitoMockObjectInputStream#resolveClass(ObjectStreamClass)}.
+ * </p>
+ *
+ */
+ private static class MockitoMockObjectOutputStream extends ObjectOutputStream {
+ private static final String NOTHING = "";
+ private MockUtil mockUtil = new MockUtil();
+
+ public MockitoMockObjectOutputStream(ByteArrayOutputStream out) throws IOException {
+ super(out);
+ }
+
+ /**
+ * Annotates (marks) the class if this class is a Mockito mock.
+ *
+ * @param cl The class to annotate.
+ * @throws IOException
+ */
+ @Override
+ protected void annotateClass(Class<?> cl) throws IOException {
+ writeObject(mockitoProxyClassMarker(cl));
+ // might be also useful later, for embedding classloader info ...maybe ...maybe not
+ }
+
+ /**
+ * Returns the Mockito marker if this class is a Mockito mock.
+ *
+ * @param cl The class to mark.
+ * @return The marker if this is a Mockito proxy class, otherwise returns a void marker.
+ */
+ private String mockitoProxyClassMarker(Class<?> cl) {
+ if (mockUtil.isMock(cl)) {
+ return MOCKITO_PROXY_MARKER;
+ } else {
+ return NOTHING;
+ }
+ }
+ }
+
+
+ /**
+ * Simple interface that hold a correct <code>writeReplace</code> signature that can be seen by an
+ * <code>ObjectOutputStream</code>.
+ *
+ * It will be applied before the creation of the mock when the mock setting says it should serializable.
+ *
+ * @see #enableSerializationAcrossJVM(org.mockito.mock.MockCreationSettings)
+ */
+ public interface AcrossJVMMockitoMockSerializable {
+ public Object writeReplace() throws java.io.ObjectStreamException;
+ }
+}
diff --git a/src/org/mockito/internal/creation/CglibMockMaker.java b/src/org/mockito/internal/creation/CglibMockMaker.java
new file mode 100644
index 0000000..63893d4
--- /dev/null
+++ b/src/org/mockito/internal/creation/CglibMockMaker.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation;
+
+import org.mockito.cglib.proxy.Callback;
+import org.mockito.cglib.proxy.Factory;
+import org.mockito.exceptions.base.MockitoException;
+import org.mockito.internal.InternalMockHandler;
+import org.mockito.invocation.MockHandler;
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.plugins.MockMaker;
+import org.mockito.internal.creation.jmock.ClassImposterizer;
+
+/**
+ * A MockMaker that uses cglib to generate mocks on a JVM.
+ */
+public final class CglibMockMaker implements MockMaker {
+
+ public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
+ InternalMockHandler mockitoHandler = cast(handler);
+ new AcrossJVMSerializationFeature().enableSerializationAcrossJVM(settings);
+ return ClassImposterizer.INSTANCE.imposterise(
+ new MethodInterceptorFilter(mockitoHandler, settings), settings.getTypeToMock(), settings.getExtraInterfaces());
+ }
+
+ private InternalMockHandler cast(MockHandler handler) {
+ if (!(handler instanceof InternalMockHandler)) {
+ throw new MockitoException("At the moment you cannot provide own implementations of MockHandler." +
+ "\nPlease see the javadocs for the MockMaker interface.");
+ }
+ return (InternalMockHandler) handler;
+ }
+
+ public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) {
+ ((Factory) mock).setCallback(0, new MethodInterceptorFilter(cast(newHandler), settings));
+ }
+
+ public MockHandler getHandler(Object mock) {
+ if (!(mock instanceof Factory)) {
+ return null;
+ }
+ Factory factory = (Factory) mock;
+ Callback callback = factory.getCallback(0);
+ if (!(callback instanceof MethodInterceptorFilter)) {
+ return null;
+ }
+ return ((MethodInterceptorFilter) callback).getHandler();
+ }
+}
diff --git a/src/org/mockito/internal/creation/DelegatingMockitoMethodProxy.java b/src/org/mockito/internal/creation/DelegatingMockitoMethodProxy.java
new file mode 100644
index 0000000..bb2477d
--- /dev/null
+++ b/src/org/mockito/internal/creation/DelegatingMockitoMethodProxy.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation;
+
+import org.mockito.cglib.proxy.MethodProxy;
+
+public class DelegatingMockitoMethodProxy extends AbstractMockitoMethodProxy {
+
+ private final MethodProxy methodProxy;
+
+ public DelegatingMockitoMethodProxy(MethodProxy methodProxy) {
+ this.methodProxy = methodProxy;
+ }
+
+ public MethodProxy getMethodProxy() {
+ return methodProxy;
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/MethodInterceptorFilter.java b/src/org/mockito/internal/creation/MethodInterceptorFilter.java
new file mode 100644
index 0000000..3d7d910
--- /dev/null
+++ b/src/org/mockito/internal/creation/MethodInterceptorFilter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.internal.creation;
+
+import org.mockito.cglib.proxy.MethodInterceptor;
+import org.mockito.cglib.proxy.MethodProxy;
+import org.mockito.internal.InternalMockHandler;
+import org.mockito.internal.creation.cglib.CGLIBHacker;
+import org.mockito.internal.invocation.InvocationImpl;
+import org.mockito.internal.invocation.MockitoMethod;
+import org.mockito.internal.invocation.SerializableMethod;
+import org.mockito.internal.invocation.realmethod.FilteredCGLIBProxyRealMethod;
+import org.mockito.internal.progress.SequenceNumber;
+import org.mockito.internal.util.ObjectMethodsGuru;
+import org.mockito.invocation.Invocation;
+import org.mockito.invocation.MockHandler;
+import org.mockito.mock.MockCreationSettings;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+/**
+ * Should be one instance per mock instance, see CglibMockMaker.
+ *
+ *
+ */
+public class MethodInterceptorFilter implements MethodInterceptor, Serializable {
+
+ private static final long serialVersionUID = 6182795666612683784L;
+ private final InternalMockHandler handler;
+ CGLIBHacker cglibHacker = new CGLIBHacker();
+ ObjectMethodsGuru objectMethodsGuru = new ObjectMethodsGuru();
+ private final MockCreationSettings mockSettings;
+ private AcrossJVMSerializationFeature acrossJVMSerializationFeature = new AcrossJVMSerializationFeature();
+
+ public MethodInterceptorFilter(InternalMockHandler handler, MockCreationSettings mockSettings) {
+ this.handler = handler;
+ this.mockSettings = mockSettings;
+ }
+
+ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
+ throws Throwable {
+ if (objectMethodsGuru.isEqualsMethod(method)) {
+ return proxy == args[0];
+ } else if (objectMethodsGuru.isHashCodeMethod(method)) {
+ return hashCodeForMock(proxy);
+ } else if (acrossJVMSerializationFeature.isWriteReplace(method)) {
+ return acrossJVMSerializationFeature.writeReplace(proxy);
+ }
+
+ MockitoMethodProxy mockitoMethodProxy = createMockitoMethodProxy(methodProxy);
+ cglibHacker.setMockitoNamingPolicy(mockitoMethodProxy);
+
+ MockitoMethod mockitoMethod = createMockitoMethod(method);
+
+ FilteredCGLIBProxyRealMethod realMethod = new FilteredCGLIBProxyRealMethod(mockitoMethodProxy);
+ Invocation invocation = new InvocationImpl(proxy, mockitoMethod, args, SequenceNumber.next(), realMethod);
+ return handler.handle(invocation);
+ }
+
+ public MockHandler getHandler() {
+ return handler;
+ }
+
+ private int hashCodeForMock(Object mock) {
+ return System.identityHashCode(mock);
+ }
+
+ public MockitoMethodProxy createMockitoMethodProxy(MethodProxy methodProxy) {
+ if (mockSettings.isSerializable())
+ return new SerializableMockitoMethodProxy(methodProxy);
+ return new DelegatingMockitoMethodProxy(methodProxy);
+ }
+
+ public MockitoMethod createMockitoMethod(Method method) {
+ if (mockSettings.isSerializable()) {
+ return new SerializableMethod(method);
+ } else {
+ return new DelegatingMethod(method);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/MockitoMethodProxy.java b/src/org/mockito/internal/creation/MockitoMethodProxy.java
new file mode 100644
index 0000000..384ca61
--- /dev/null
+++ b/src/org/mockito/internal/creation/MockitoMethodProxy.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation;
+
+import org.mockito.cglib.proxy.MethodProxy;
+
+public interface MockitoMethodProxy {
+
+ Object invokeSuper(Object target, Object[] arguments) throws Throwable;
+
+ MethodProxy getMethodProxy();
+
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/SerializableMockitoMethodProxy.java b/src/org/mockito/internal/creation/SerializableMockitoMethodProxy.java
new file mode 100644
index 0000000..0646083
--- /dev/null
+++ b/src/org/mockito/internal/creation/SerializableMockitoMethodProxy.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation;
+
+import java.io.Serializable;
+
+import org.mockito.cglib.proxy.MethodProxy;
+import org.mockito.internal.util.reflection.Whitebox;
+
+public class SerializableMockitoMethodProxy extends AbstractMockitoMethodProxy implements Serializable {
+
+ private static final long serialVersionUID = -5337859962876770632L;
+ private final Class<?> c1;
+ private final Class<?> c2;
+ private final String desc;
+ private final String name;
+ private final String superName;
+ private transient MethodProxy methodProxy;
+
+ public SerializableMockitoMethodProxy(MethodProxy methodProxy) {
+ Object info = Whitebox.getInternalState(methodProxy, "createInfo");
+ c1 = (Class<?>) Whitebox.getInternalState(info, "c1");
+ c2 = (Class<?>) Whitebox.getInternalState(info, "c2");
+ desc = methodProxy.getSignature().getDescriptor();
+ name = methodProxy.getSignature().getName();
+ superName = methodProxy.getSuperName();
+ this.methodProxy = methodProxy;
+ }
+
+ public MethodProxy getMethodProxy() {
+ if (methodProxy == null)
+ methodProxy = MethodProxy.create(c1, c2, desc, name, superName);
+ return methodProxy;
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/cglib/CGLIBHacker.java b/src/org/mockito/internal/creation/cglib/CGLIBHacker.java
new file mode 100644
index 0000000..e0ce914
--- /dev/null
+++ b/src/org/mockito/internal/creation/cglib/CGLIBHacker.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.cglib;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+
+import org.mockito.internal.creation.MockitoMethodProxy;
+import org.mockito.cglib.proxy.MethodProxy;
+
+public class CGLIBHacker implements Serializable {
+
+ private static final long serialVersionUID = -4389233991416356668L;
+
+ public void setMockitoNamingPolicy(MockitoMethodProxy mockitoMethodProxy) {
+ try {
+ MethodProxy methodProxy = mockitoMethodProxy.getMethodProxy();
+ Field createInfoField = reflectOnCreateInfo(methodProxy);
+ createInfoField.setAccessible(true);
+ Object createInfo = createInfoField.get(methodProxy);
+ Field namingPolicyField = createInfo.getClass().getDeclaredField("namingPolicy");
+ namingPolicyField.setAccessible(true);
+ if (namingPolicyField.get(createInfo) == null) {
+ namingPolicyField.set(createInfo, MockitoNamingPolicy.INSTANCE);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Unable to set MockitoNamingPolicy on cglib generator which creates FastClasses", e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Field reflectOnCreateInfo(MethodProxy methodProxy) throws SecurityException, NoSuchFieldException {
+
+ Class cglibMethodProxyClass = methodProxy.getClass();
+ // in case methodProxy was extended by user, let's traverse the object
+ // graph to find the cglib methodProxy
+ // with all the fields we would like to change
+ while (cglibMethodProxyClass != MethodProxy.class) {
+ cglibMethodProxyClass = methodProxy.getClass().getSuperclass();
+ }
+ return cglibMethodProxyClass.getDeclaredField("createInfo");
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/cglib/MockitoNamingPolicy.java b/src/org/mockito/internal/creation/cglib/MockitoNamingPolicy.java
new file mode 100644
index 0000000..c646ccd
--- /dev/null
+++ b/src/org/mockito/internal/creation/cglib/MockitoNamingPolicy.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.cglib;
+
+import org.mockito.cglib.core.DefaultNamingPolicy;
+
+public class MockitoNamingPolicy extends DefaultNamingPolicy {
+
+ public static final MockitoNamingPolicy INSTANCE = new MockitoNamingPolicy();
+
+ @Override
+ protected String getTag() {
+ return "ByMockitoWithCGLIB";
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/cglib/package.html b/src/org/mockito/internal/creation/cglib/package.html
new file mode 100644
index 0000000..d195d54
--- /dev/null
+++ b/src/org/mockito/internal/creation/cglib/package.html
@@ -0,0 +1,6 @@
+<!--
+ ~ Copyright (c) 2007 Mockito contributors
+ ~ This program is made available under the terms of the MIT License.
+ -->
+
+<body>CGLIB related stuff</body> \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/jmock/ClassImposterizer.java b/src/org/mockito/internal/creation/jmock/ClassImposterizer.java
new file mode 100644
index 0000000..2e5ebcb
--- /dev/null
+++ b/src/org/mockito/internal/creation/jmock/ClassImposterizer.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.jmock;
+
+import org.mockito.cglib.core.CodeGenerationException;
+import org.mockito.cglib.core.NamingPolicy;
+import org.mockito.cglib.core.Predicate;
+import org.mockito.cglib.proxy.*;
+import org.mockito.exceptions.base.MockitoException;
+import org.mockito.internal.configuration.GlobalConfiguration;
+import org.mockito.internal.creation.cglib.MockitoNamingPolicy;
+import org.objenesis.ObjenesisStd;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.List;
+
+import static org.mockito.internal.util.StringJoiner.join;
+
+/**
+ * Thanks to jMock guys for this handy class that wraps all the cglib magic.
+ */
+public class ClassImposterizer {
+
+ public static final ClassImposterizer INSTANCE = new ClassImposterizer();
+
+ private ClassImposterizer() {}
+
+ //TODO: in order to provide decent exception message when objenesis is not found,
+ //have a constructor in this class that tries to instantiate ObjenesisStd and if it fails then show decent exception that dependency is missing
+ //TODO: for the same reason catch and give better feedback when hamcrest core is not found.
+ private ObjenesisStd objenesis = new ObjenesisStd(new GlobalConfiguration().enableClassCache());
+
+ private static final NamingPolicy NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES = new MockitoNamingPolicy() {
+ @Override
+ public String getClassName(String prefix, String source, Object key, Predicate names) {
+ return "codegen." + super.getClassName(prefix, source, key, names);
+ }
+ };
+
+ private static final CallbackFilter IGNORE_BRIDGE_METHODS = new CallbackFilter() {
+ public int accept(Method method, List<Method> allMethods) {
+ return method.isBridge() ? 1 : 0;
+ }
+ };
+
+ public <T> T imposterise(final MethodInterceptor interceptor, Class<T> mockedType, Collection<Class> ancillaryTypes) {
+ return imposterise(interceptor, mockedType, ancillaryTypes.toArray(new Class[ancillaryTypes.size()]));
+ }
+
+ public <T> T imposterise(final MethodInterceptor interceptor, Class<T> mockedType, Class<?>... ancillaryTypes) {
+ Class<?> proxyClass = null;
+ Object proxyInstance = null;
+ try {
+ setConstructorsAccessible(mockedType, true);
+ proxyClass = createProxyClass(mockedType, ancillaryTypes);
+ proxyInstance = createProxy(proxyClass, interceptor);
+ return mockedType.cast(proxyInstance);
+ } catch (ClassCastException cce) {
+ // NPE unlikely to happen because CCE will only happen on the cast statement
+ throw new MockitoException(join(
+ "ClassCastException occurred while creating the mockito proxy :",
+ " class to imposterize : '" + mockedType.getCanonicalName() + "', loaded by classloader : '" + mockedType.getClassLoader() + "'",
+ " imposterizing class : '" + proxyClass.getCanonicalName() + "', loaded by classloader : '" + proxyClass.getClassLoader() + "'",
+ " proxy instance class : '" + proxyInstance.getClass().getCanonicalName() + "', loaded by classloader : '" + proxyInstance.getClass().getClassLoader() + "'",
+ "",
+ "You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration)"
+ ), cce);
+ } finally {
+ setConstructorsAccessible(mockedType, false);
+ }
+ }
+
+ public void setConstructorsAccessible(Class<?> mockedType, boolean accessible) {
+ for (Constructor<?> constructor : mockedType.getDeclaredConstructors()) {
+ constructor.setAccessible(accessible);
+ }
+ }
+
+ public Class<?> createProxyClass(Class<?> mockedType, Class<?>... interfaces) {
+ if (mockedType == Object.class) {
+ mockedType = ClassWithSuperclassToWorkAroundCglibBug.class;
+ }
+
+ Enhancer enhancer = new Enhancer() {
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void filterConstructors(Class sc, List constructors) {
+ // Don't filter
+ }
+ };
+ enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(mockedType));
+ enhancer.setUseFactory(true);
+ if (mockedType.isInterface()) {
+ enhancer.setSuperclass(Object.class);
+ enhancer.setInterfaces(prepend(mockedType, interfaces));
+ } else {
+ enhancer.setSuperclass(mockedType);
+ enhancer.setInterfaces(interfaces);
+ }
+ enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class});
+ enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS);
+ if (mockedType.getSigners() != null) {
+ enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES);
+ } else {
+ enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE);
+ }
+
+ enhancer.setSerialVersionUID(42L);
+
+ try {
+ return enhancer.createClass();
+ } catch (CodeGenerationException e) {
+ if (Modifier.isPrivate(mockedType.getModifiers())) {
+ throw new MockitoException("\n"
+ + "Mockito cannot mock this class: " + mockedType
+ + ".\n"
+ + "Most likely it is a private class that is not visible by Mockito");
+ }
+ throw new MockitoException("\n"
+ + "Mockito cannot mock this class: " + mockedType
+ + "\n"
+ + "Mockito can only mock visible & non-final classes."
+ + "\n"
+ + "If you're not sure why you're getting this error, please report to the mailing list.", e);
+ }
+ }
+
+ private Object createProxy(Class<?> proxyClass, final MethodInterceptor interceptor) {
+ Factory proxy = (Factory) objenesis.newInstance(proxyClass);
+ proxy.setCallbacks(new Callback[] {interceptor, SerializableNoOp.SERIALIZABLE_INSTANCE });
+ return proxy;
+ }
+
+ private Class<?>[] prepend(Class<?> first, Class<?>... rest) {
+ Class<?>[] all = new Class<?>[rest.length+1];
+ all[0] = first;
+ System.arraycopy(rest, 0, all, 1, rest.length);
+ return all;
+ }
+
+ public static class ClassWithSuperclassToWorkAroundCglibBug {}
+
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/jmock/SearchingClassLoader.java b/src/org/mockito/internal/creation/jmock/SearchingClassLoader.java
new file mode 100644
index 0000000..85d741e
--- /dev/null
+++ b/src/org/mockito/internal/creation/jmock/SearchingClassLoader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.jmock;
+
+import static java.lang.Thread.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Thanks to jMock guys for this ClassLoader.
+ */
+public class SearchingClassLoader extends ClassLoader {
+ private final ClassLoader nextToSearch;
+
+ public SearchingClassLoader(ClassLoader parent, ClassLoader nextToSearch) {
+ super(parent);
+ this.nextToSearch = nextToSearch;
+ }
+
+ public static ClassLoader combineLoadersOf(Class<?>... classes) {
+ return combineLoadersOf(classes[0], classes);
+ }
+
+ private static ClassLoader combineLoadersOf(Class<?> first, Class<?>... others) {
+ List<ClassLoader> loaders = new ArrayList<ClassLoader>();
+
+ addIfNewElement(loaders, first.getClassLoader());
+ for (Class<?> c : others) {
+ addIfNewElement(loaders, c.getClassLoader());
+ }
+
+ // To support Eclipse Plug-in tests.
+ // In an Eclipse plug-in, jMock itself will not be on the system class loader
+ // but in the class loader of the plug-in.
+ //
+ // Note: I've been unable to reproduce the error in jMock's test suite.
+ addIfNewElement(loaders, SearchingClassLoader.class.getClassLoader());
+
+ // To support the Maven Surefire plugin.
+ // Note: I've been unable to reproduce the error in jMock's test suite.
+ addIfNewElement(loaders, currentThread().getContextClassLoader());
+
+ //Had to comment that out because it didn't work with in-container Spring tests
+ //addIfNewElement(loaders, ClassLoader.getSystemClassLoader());
+
+ return combine(loaders);
+ }
+
+ private static ClassLoader combine(List<ClassLoader> parentLoaders) {
+ ClassLoader loader = parentLoaders.get(parentLoaders.size()-1);
+
+ for (int i = parentLoaders.size()-2; i >= 0; i--) {
+ loader = new SearchingClassLoader(parentLoaders.get(i), loader);
+ }
+
+ return loader;
+ }
+
+ private static void addIfNewElement(List<ClassLoader> loaders, ClassLoader c) {
+ if (c != null && !loaders.contains(c)) {
+ loaders.add(c);
+ }
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (nextToSearch != null) {
+ return nextToSearch.loadClass(name);
+ } else {
+ return super.findClass(name); // will throw ClassNotFoundException
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/jmock/SerializableNoOp.java b/src/org/mockito/internal/creation/jmock/SerializableNoOp.java
new file mode 100644
index 0000000..c5608e7
--- /dev/null
+++ b/src/org/mockito/internal/creation/jmock/SerializableNoOp.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.creation.jmock;
+
+import org.mockito.cglib.proxy.Callback;
+import org.mockito.cglib.proxy.NoOp;
+
+import java.io.Serializable;
+
+/**
+ * Offer a Serializable implementation of the NoOp CGLIB callback.
+ */
+public class SerializableNoOp implements NoOp, Serializable {
+
+ private static final long serialVersionUID = 7434976328690189159L;
+ public static final Callback SERIALIZABLE_INSTANCE = new SerializableNoOp();
+
+}
diff --git a/src/org/mockito/internal/creation/jmock/jmock-license.txt b/src/org/mockito/internal/creation/jmock/jmock-license.txt
new file mode 100644
index 0000000..4c56c9c
--- /dev/null
+++ b/src/org/mockito/internal/creation/jmock/jmock-license.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2000-2007, jMock.org
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of
+conditions and the following disclaimer. Redistributions in binary form must reproduce
+the above copyright notice, this list of conditions and the following disclaimer in
+the documentation and/or other materials provided with the distribution.
+
+Neither the name of jMock nor the names of its contributors may be used to endorse
+or promote products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE. \ No newline at end of file
diff --git a/src/org/mockito/internal/creation/jmock/package.html b/src/org/mockito/internal/creation/jmock/package.html
new file mode 100644
index 0000000..39c142b
--- /dev/null
+++ b/src/org/mockito/internal/creation/jmock/package.html
@@ -0,0 +1,6 @@
+<!--
+ ~ Copyright (c) 2007 Mockito contributors
+ ~ This program is made available under the terms of the MIT License.
+ -->
+
+<body>Borrowed from jmock codebase</body> \ No newline at end of file
diff --git a/src/org/mockito/internal/invocation/realmethod/CGLIBProxyRealMethod.java b/src/org/mockito/internal/invocation/realmethod/CGLIBProxyRealMethod.java
new file mode 100644
index 0000000..140ae8e
--- /dev/null
+++ b/src/org/mockito/internal/invocation/realmethod/CGLIBProxyRealMethod.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.invocation.realmethod;
+
+import java.io.Serializable;
+
+import org.mockito.internal.creation.MockitoMethodProxy;
+
+
+public class CGLIBProxyRealMethod implements RealMethod, HasCGLIBMethodProxy, Serializable {
+
+ private static final long serialVersionUID = -4596470901191501582L;
+ private final MockitoMethodProxy methodProxy;
+
+ public CGLIBProxyRealMethod(MockitoMethodProxy methodProxy) {
+ this.methodProxy = methodProxy;
+ }
+
+ public Object invoke(Object target, Object[] arguments) throws Throwable {
+ return methodProxy.invokeSuper(target, arguments);
+ }
+
+ public MockitoMethodProxy getMethodProxy() {
+ return methodProxy;
+ }
+}
diff --git a/src/org/mockito/internal/invocation/realmethod/FilteredCGLIBProxyRealMethod.java b/src/org/mockito/internal/invocation/realmethod/FilteredCGLIBProxyRealMethod.java
new file mode 100644
index 0000000..39c3b86
--- /dev/null
+++ b/src/org/mockito/internal/invocation/realmethod/FilteredCGLIBProxyRealMethod.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.invocation.realmethod;
+
+import org.mockito.internal.creation.MockitoMethodProxy;
+import org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter;
+
+import java.io.Serializable;
+
+public class FilteredCGLIBProxyRealMethod implements RealMethod, HasCGLIBMethodProxy, Serializable {
+
+ private static final long serialVersionUID = 3596550785818938496L;
+ private final RealMethod realMethod;
+
+ public FilteredCGLIBProxyRealMethod(MockitoMethodProxy methodProxy) {
+ this(new CGLIBProxyRealMethod(methodProxy));
+ }
+
+ public FilteredCGLIBProxyRealMethod(RealMethod realMethod) {
+ this.realMethod = realMethod;
+ }
+
+ public Object invoke(Object target, Object[] arguments) throws Throwable {
+ try {
+ return realMethod.invoke(target, arguments);
+ } catch (Throwable t) {
+ new ConditionalStackTraceFilter().filter(t);
+ throw t;
+ }
+ }
+
+ public MockitoMethodProxy getMethodProxy() {
+ return ((HasCGLIBMethodProxy) realMethod).getMethodProxy();
+ }
+} \ No newline at end of file
diff --git a/src/org/mockito/internal/invocation/realmethod/HasCGLIBMethodProxy.java b/src/org/mockito/internal/invocation/realmethod/HasCGLIBMethodProxy.java
new file mode 100644
index 0000000..299bc16
--- /dev/null
+++ b/src/org/mockito/internal/invocation/realmethod/HasCGLIBMethodProxy.java
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.invocation.realmethod;
+
+import java.io.Serializable;
+
+import org.mockito.internal.creation.MockitoMethodProxy;
+
+public interface HasCGLIBMethodProxy extends Serializable {
+
+ MockitoMethodProxy getMethodProxy();
+}