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.reflect.ParameterizedType;
11  import java.lang.reflect.Proxy;
12  import java.lang.reflect.Type;
13  import java.lang.reflect.TypeVariable;
14  import java.util.ArrayList;
15  import java.util.List;
16  
17  /**
18   * This marker interface exists only to guarantee that JMockit can get the bytecode definition of each Proxy class it
19   * creates through <code>java.lang.reflect.Proxy</code>. If such a class is created before JMockit is initialized, its
20   * bytecode won't be stored in JMockit's cache. And since the JDK uses an internal cache for proxy classes, it won't
21   * create a new one, therefore not going through the ProxyRegistrationTransformer. So, by always implementing this
22   * additional interface, we can guarantee a new proxy class will be created when JMockit first requests it for a given
23   * interface.
24   */
25  public interface EmptyProxy {
26      final class Impl {
27          private Impl() {
28          }
29  
30          @NonNull
31          public static <E> E newEmptyProxy(@Nullable ClassLoader loader, @NonNull Type... interfacesToBeProxied) {
32              List<Class<?>> interfaces = new ArrayList<>();
33  
34              for (Type type : interfacesToBeProxied) {
35                  addInterface(interfaces, type);
36              }
37  
38              if (loader == null) {
39                  // noinspection AssignmentToMethodParameter
40                  loader = interfaces.get(0).getClassLoader();
41              }
42  
43              if (loader == EmptyProxy.class.getClassLoader()) {
44                  interfaces.add(EmptyProxy.class);
45              }
46  
47              Class<?>[] interfacesArray = interfaces.toArray(new Class<?>[interfaces.size()]);
48  
49              // noinspection unchecked
50              return (E) Proxy.newProxyInstance(loader, interfacesArray, MockInvocationHandler.INSTANCE);
51          }
52  
53          private static void addInterface(@NonNull List<Class<?>> interfaces, @NonNull Type type) {
54              if (type instanceof Class<?>) {
55                  interfaces.add((Class<?>) type);
56              } else if (type instanceof ParameterizedType) {
57                  ParameterizedType paramType = (ParameterizedType) type;
58                  interfaces.add((Class<?>) paramType.getRawType());
59              } else if (type instanceof TypeVariable) {
60                  TypeVariable<?> typeVar = (TypeVariable<?>) type;
61                  addBoundInterfaces(interfaces, typeVar.getBounds());
62              }
63          }
64  
65          private static void addBoundInterfaces(@NonNull List<Class<?>> interfaces, @NonNull Type[] bounds) {
66              for (Type bound : bounds) {
67                  addInterface(interfaces, bound);
68              }
69          }
70      }
71  }