View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit.internal;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.lang.reflect.Constructor;
11  import java.lang.reflect.Member;
12  import java.lang.reflect.Method;
13  
14  import mockit.Invocation;
15  import mockit.internal.reflection.MethodReflection;
16  
17  import org.checkerframework.checker.index.qual.NonNegative;
18  
19  /**
20   * Base class for encapsulating state and logic needed by both the Mocking and Faking APIs, but which should not go into
21   * {@link Invocation} in order to keep the published API clean.
22   */
23  public abstract class BaseInvocation extends Invocation {
24      @Nullable
25      private Member realMember;
26      @Nullable
27      private BaseInvocation previousInvocation;
28  
29      protected BaseInvocation(@Nullable Object invokedInstance, @NonNull Object[] invokedArguments,
30              @NonNegative int invocationCount) {
31          super(invokedInstance, invokedArguments, invocationCount);
32      }
33  
34      @NonNull
35      public final Member getRealMember() {
36          if (realMember == null) {
37              realMember = findRealMember();
38          }
39  
40          return realMember;
41      }
42  
43      @NonNull
44      protected abstract Member findRealMember();
45  
46      @Nullable
47      public final <T> T doProceed(@Nullable Object[] replacementArguments) {
48          Member memberToInvoke = getRealMember();
49  
50          if (memberToInvoke instanceof Constructor) {
51              prepareToProceed();
52              return null;
53          }
54  
55          prepareToProceed();
56  
57          Method realMethod = (Method) memberToInvoke;
58          Object[] actualArgs = getInvokedArguments();
59  
60          if (replacementArguments != null && replacementArguments.length > 0) {
61              actualArgs = replacementArguments;
62          }
63  
64          try {
65              return MethodReflection.invoke(getInvokedInstance(), realMethod, actualArgs);
66          } finally {
67              cleanUpAfterProceed();
68          }
69      }
70  
71      public abstract void prepareToProceed();
72  
73      protected abstract void cleanUpAfterProceed();
74  
75      @Nullable
76      public final BaseInvocation getPrevious() {
77          return previousInvocation;
78      }
79  
80      public final void setPrevious(@NonNull BaseInvocation previous) {
81          previousInvocation = previous;
82      }
83  
84      public final boolean isMethodInSuperclass(@Nullable Object mock, @NonNull String classDesc) {
85          if (mock != null && mock == getInvokedInstance() && getInvokedMember() instanceof Method) {
86              Method methodToInvoke = getInvokedMember();
87              String invokedClassDesc = methodToInvoke.getDeclaringClass().getName().replace('.', '/');
88              return !invokedClassDesc.equals(classDesc);
89          }
90  
91          return previousInvocation != null && previousInvocation.isMethodInSuperclass(mock, classDesc);
92      }
93  }