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.reflection;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.lang.annotation.Annotation;
11  import java.lang.reflect.Constructor;
12  import java.lang.reflect.InvocationHandler;
13  import java.lang.reflect.Method;
14  
15  import mockit.internal.util.DefaultValues;
16  import mockit.internal.util.ObjectMethods;
17  
18  /**
19   * Handles invocations to all kinds of mock implementations created for interfaces and annotation types through any of
20   * the mocking APIs.
21   * <p>
22   * The <code>java.lang.Object</code> methods <code>equals</code>, <code>hashCode</code>, and <code>toString</code> are
23   * handled in a meaningful way, returning a value that makes sense for the proxy instance. The special
24   * {@linkplain Annotation} contracts for these three methods is <em>not</em> observed, though, since it would require
25   * making dynamic calls to the mocked annotation attributes.
26   * <p>
27   * Any other method invocation is handled by simply returning the default value according to the method's return type
28   * (as defined in {@linkplain DefaultValues}).
29   */
30  public final class MockInvocationHandler implements InvocationHandler {
31      public static final InvocationHandler INSTANCE = new MockInvocationHandler();
32      private static final Class<?>[] CONSTRUCTOR_PARAMETERS_FOR_PROXY_CLASS = { InvocationHandler.class };
33  
34      @NonNull
35      public static Object newMockedInstance(@NonNull Class<?> proxyClass) {
36          Constructor<?> publicConstructor;
37          try {
38              publicConstructor = proxyClass.getConstructor(CONSTRUCTOR_PARAMETERS_FOR_PROXY_CLASS);
39          } catch (NoSuchMethodException e) {
40              throw new RuntimeException(e);
41          }
42  
43          return ConstructorReflection.invokeAccessible(publicConstructor, INSTANCE);
44      }
45  
46      @Nullable
47      @Override
48      public Object invoke(@NonNull Object proxy, @NonNull Method method, @Nullable Object[] args) {
49          Class<?> declaringClass = method.getDeclaringClass();
50          String methodName = method.getName();
51  
52          if (declaringClass == Object.class) {
53              if ("equals".equals(methodName)) {
54                  assert args != null;
55                  return proxy == args[0];
56              }
57              if ("hashCode".equals(methodName)) {
58                  return System.identityHashCode(proxy);
59              }
60              // "toString"
61              return ObjectMethods.objectIdentity(proxy);
62          }
63  
64          if (declaringClass == Annotation.class) {
65              return proxy.getClass().getInterfaces()[0];
66          }
67  
68          Class<?> retType = method.getReturnType();
69          return DefaultValues.computeForType(retType);
70      }
71  }