Class AcrossJVMSerializationFeature

  • All Implemented Interfaces:
    java.io.Serializable

    @Incubating
    class AcrossJVMSerializationFeature
    extends java.lang.Object
    implements java.io.Serializable
    This is responsible for serializing a mock, it is enabled if the mock is implementing Serializable.

    The way it works is to enable serialization via the enableSerializationAcrossJVM(MockCreationSettings), if the mock settings is set to be serializable it will add the AcrossJVMSerializationFeature.AcrossJVMMockitoMockSerializable interface. This interface defines a the AcrossJVMSerializationFeature.AcrossJVMMockitoMockSerializable.writeReplace() whose signature match the one that is looked by the standard Java serialization.

    Then in the MethodInterceptorFilter of mockito, if the writeReplace method is called, it will use the custom implementation of this class writeReplace(Object). This method has a specific knowledge on how to serialize a mockito mock that is based on CGLIB.

    Only one instance per mock! See MethodInterceptorFilter

    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
    Since:
    1.10.0
    See Also:
    CglibMockMaker, MethodInterceptorFilter
    • Field Detail

      • MOCKITO_PROXY_MARKER

        private static final java.lang.String MOCKITO_PROXY_MARKER
        See Also:
        Constant Field Values
      • instanceLocalCurrentlySerializingFlag

        private boolean instanceLocalCurrentlySerializingFlag
      • mutex

        private final java.util.concurrent.locks.Lock mutex
    • Constructor Detail

      • AcrossJVMSerializationFeature

        AcrossJVMSerializationFeature()
    • Method Detail

      • isWriteReplace

        public boolean isWriteReplace​(java.lang.reflect.Method method)
      • writeReplace

        public java.lang.Object writeReplace​(java.lang.Object mockitoMock)
                                      throws java.io.ObjectStreamException
        Custom implementation of the writeReplace method for serialization. Here's how it's working and why :
        1. When first entering in this method, it's because some is serializing the mock, with some code like :

          
               objectOutputStream.writeObject(mock);
           
          So, ObjectOutputStream will track the writeReplace 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 AcrossJVMSerializationFeature.AcrossJVMMockSerializationProxy.

        2. Now, in the constructor AcrossJVMMockSerializationProxy(Object) the mock is being serialized in a custom way (using AcrossJVMSerializationFeature.MockitoMockObjectOutputStream) to a byte array. So basically it means the code is performing double nested serialization of the passed mockitoMock.

          However the ObjectOutputStream will still detect the custom writeReplace and execute it. (For that matter disabling replacement via ObjectOutputStream.enableReplaceObject(boolean) doesn't disable the writeReplace call, but just just toggle replacement in the written stream, writeReplace is always called by ObjectOutputStream.)

          In order to avoid this recursion, obviously leading to a StackOverflowError, this method is using a flag that marks the mock as already being replaced, and then shouldn't replace itself again. This flag is local to this class, which means the flag of this class unfortunately needs to be protected against concurrent access, hence the reentrant lock.

        Parameters:
        mockitoMock - The Mockito mock to be serialized.
        Returns:
        A wrapper (AcrossJVMSerializationFeature.AcrossJVMMockSerializationProxy) to be serialized by the calling ObjectOutputStream.
        Throws:
        java.io.ObjectStreamException
      • mockReplacementCompleted

        private void mockReplacementCompleted()
      • mockReplacementStarted

        private void mockReplacementStarted()
      • mockIsCurrentlyBeingReplaced

        private boolean mockIsCurrentlyBeingReplaced()
      • enableSerializationAcrossJVM

        public <T> void enableSerializationAcrossJVM​(org.mockito.mock.MockCreationSettings<T> settings)
        Enable serialization serialization that will work across classloaders / and JVM.

        Only enable if settings says the mock should be serializable. In this case add the AcrossJVMSerializationFeature.AcrossJVMMockitoMockSerializable to the extra interface list.

        Type Parameters:
        T - Type param to not be bothered by the generics
        Parameters:
        settings - Mock creation settings.