Search in sources :

Example 1 with MockitoSerializationIssue

use of org.mockito.exceptions.base.MockitoSerializationIssue in project mockito by mockito.

the class ByteBuddyCrossClassLoaderSerializationSupport method writeReplace.

/**
     * Custom implementation of the <code>writeReplace</code> method for serialization.
     * <p/>
     * 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 :</p>
     *
     * <pre class="code"><code class="java">
     * objectOutputStream.writeObject(mock);
     * </code></pre>
     *
     *         <p>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 CrossClassLoaderSerializableMock}.</p>
     *     </li>
     *     <li>
     *         <p>Now, in the constructor
     *         {@link CrossClassLoaderSerializationProxy#CrossClassLoaderSerializationProxy(java.lang.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 CrossClassLoaderSerializationProxy}) to be serialized by the calling ObjectOutputStream.
     * @throws java.io.ObjectStreamException
     */
public Object writeReplace(Object mockitoMock) throws ObjectStreamException {
    // reentrant lock for critical section. could it be improved ?
    mutex.lock();
    try {
        // temporary loosy hack to avoid stackoverflow
        if (mockIsCurrentlyBeingReplaced()) {
            return mockitoMock;
        }
        mockReplacementStarted();
        return new CrossClassLoaderSerializationProxy(mockitoMock);
    } catch (IOException ioe) {
        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();
    }
}
Also used : MockName(org.mockito.mock.MockName) MockitoSerializationIssue(org.mockito.exceptions.base.MockitoSerializationIssue)

Example 2 with MockitoSerializationIssue

use of org.mockito.exceptions.base.MockitoSerializationIssue in project powermock by powermock.

the class AcrossJVMSerializationFeature method writeReplace.

/**
     * Custom implementation of the <code>writeReplace</code> method for serialization.
     * <p/>
     * 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 AcrossJVMSerializationFeature.AcrossJVMMockSerializationProxy}.</p>
     *     </li>
     *     <li>
     *         <p>Now, in the constructor
     *         {@link AcrossJVMSerializationFeature.AcrossJVMMockSerializationProxy#AcrossJVMMockSerializationProxy(Object)}
     *         the mock is being serialized in a custom way (using
     *         {@link AcrossJVMSerializationFeature.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();
        // temporary loosy hack to avoid stackoverflow
        if (mockIsCurrentlyBeingReplaced()) {
            return mockitoMock;
        }
        mockReplacementStarted();
        return new AcrossJVMMockSerializationProxy(mockitoMock);
    } catch (IOException ioe) {
        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();
    }
}
Also used : MockName(org.mockito.mock.MockName) IOException(java.io.IOException) MockitoSerializationIssue(org.mockito.exceptions.base.MockitoSerializationIssue)

Aggregations

MockitoSerializationIssue (org.mockito.exceptions.base.MockitoSerializationIssue)2 MockName (org.mockito.mock.MockName)2 IOException (java.io.IOException)1