1/*
2 * Copyright (c) 2016 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockito.internal.creation.bytebuddy;
6
7import net.bytebuddy.implementation.bind.annotation.*;
8import org.mockito.internal.InternalMockHandler;
9import org.mockito.internal.creation.DelegatingMethod;
10import org.mockito.internal.invocation.MockitoMethod;
11import org.mockito.internal.invocation.SerializableMethod;
12import org.mockito.internal.progress.SequenceNumber;
13import org.mockito.invocation.MockHandler;
14import org.mockito.mock.MockCreationSettings;
15
16import java.io.ObjectStreamException;
17import java.io.Serializable;
18import java.lang.reflect.Method;
19import java.util.concurrent.Callable;
20
21public class MockMethodInterceptor implements Serializable {
22
23    private static final long serialVersionUID = 7152947254057253027L;
24
25    final InternalMockHandler handler;
26
27    private final MockCreationSettings mockCreationSettings;
28
29    private final ByteBuddyCrossClassLoaderSerializationSupport serializationSupport;
30
31    public MockMethodInterceptor(InternalMockHandler handler, MockCreationSettings mockCreationSettings) {
32        this.handler = handler;
33        this.mockCreationSettings = mockCreationSettings;
34        serializationSupport = new ByteBuddyCrossClassLoaderSerializationSupport();
35    }
36
37    Object doIntercept(Object mock,
38                       Method invokedMethod,
39                       Object[] arguments,
40                       InterceptedInvocation.SuperMethod superMethod) throws Throwable {
41        return handler.handle(new InterceptedInvocation(
42                mock,
43                createMockitoMethod(invokedMethod),
44                arguments,
45                superMethod,
46                SequenceNumber.next()
47        ));
48    }
49
50    private MockitoMethod createMockitoMethod(Method method) {
51        if (mockCreationSettings.isSerializable()) {
52            return new SerializableMethod(method);
53        } else {
54            return new DelegatingMethod(method);
55        }
56    }
57
58    public MockHandler getMockHandler() {
59        return handler;
60    }
61
62    public ByteBuddyCrossClassLoaderSerializationSupport getSerializationSupport() {
63        return serializationSupport;
64    }
65
66    public static class ForHashCode {
67
68        @SuppressWarnings("unused")
69        public static int doIdentityHashCode(@This Object thiz) {
70            return System.identityHashCode(thiz);
71        }
72    }
73
74    public static class ForEquals {
75
76        @SuppressWarnings("unused")
77        public static boolean doIdentityEquals(@This Object thiz, @Argument(0) Object other) {
78            return thiz == other;
79        }
80    }
81
82    public static class ForWriteReplace {
83
84        public static Object doWriteReplace(@This MockAccess thiz) throws ObjectStreamException {
85            return thiz.getMockitoInterceptor().getSerializationSupport().writeReplace(thiz);
86        }
87    }
88
89    public static class DispatcherDefaultingToRealMethod {
90
91        @SuppressWarnings("unused")
92        @RuntimeType
93        @BindingPriority(BindingPriority.DEFAULT * 2)
94        public static Object interceptSuperCallable(@This Object mock,
95                                                    @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor,
96                                                    @Origin Method invokedMethod,
97                                                    @AllArguments Object[] arguments,
98                                                    @SuperCall(serializableProxy = true) Callable<?> superCall) throws Throwable {
99            if (interceptor == null) {
100                return superCall.call();
101            }
102            return interceptor.doIntercept(
103                    mock,
104                    invokedMethod,
105                    arguments,
106                    new InterceptedInvocation.SuperMethod.FromCallable(superCall)
107            );
108        }
109
110        @SuppressWarnings("unused")
111        @RuntimeType
112        public static Object interceptAbstract(@This Object mock,
113                                               @FieldValue("mockitoInterceptor") MockMethodInterceptor interceptor,
114                                               @StubValue Object stubValue,
115                                               @Origin Method invokedMethod,
116                                               @AllArguments Object[] arguments) throws Throwable {
117            if (interceptor == null) {
118                return stubValue;
119            }
120            return interceptor.doIntercept(
121                    mock,
122                    invokedMethod,
123                    arguments,
124                    InterceptedInvocation.SuperMethod.IsIllegal.INSTANCE
125            );
126        }
127    }
128}
129