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