/* * Copyright (c) 2006-2012 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit.internal.util; import java.lang.reflect.*; import java.util.*; /** * This marker interface exists only to guarantee that JMockit can get the bytecode definition of * each Proxy class it creates through <code>java.lang.reflect.Proxy</code>. * If such a class is created before JMockit is initialized, its bytecode won't be stored in * JMockit's cache. And since the JDK uses an internal cache for proxy classes, it won't create a * new one, therefore not going through the ProxyRegistrationTransformer. So, by always implementing * this additional interface, we can guarantee a new proxy class will be created when JMockit first * requests it for a given interface. */ public interface EmptyProxy { final class Impl { public static <E> E newEmptyProxy(ClassLoader loader, Class<E> interfaceToBeProxied) { Class<?>[] interfaces = loader == null ? new Class<?>[] {interfaceToBeProxied} : new Class<?>[] {interfaceToBeProxied, EmptyProxy.class}; //noinspection unchecked return (E) Proxy.newProxyInstance(loader, interfaces, MockInvocationHandler.INSTANCE); } public static <E> E newEmptyProxy(ClassLoader loader, Type... interfacesToBeProxied) { List<Class<?>> interfaces = new ArrayList<Class<?>>(); for (Type type : interfacesToBeProxied) { addInterface(interfaces, type); } if (loader == null) { //noinspection AssignmentToMethodParameter loader = interfaces.get(0).getClassLoader(); } if (loader == EmptyProxy.class.getClassLoader()) { interfaces.add(EmptyProxy.class); } Class<?>[] interfacesArray = interfaces.toArray(new Class<?>[interfaces.size()]); //noinspection unchecked return (E) Proxy.newProxyInstance(loader, interfacesArray, MockInvocationHandler.INSTANCE); } private static void addInterface(List<Class<?>> interfaces, Type type) { if (type instanceof Class<?>) { interfaces.add((Class<?>) type); } else if (type instanceof ParameterizedType) { ParameterizedType paramType = (ParameterizedType) type; interfaces.add((Class<?>) paramType.getRawType()); } else if (type instanceof TypeVariable) { TypeVariable<?> typeVar = (TypeVariable<?>) type; addBoundInterfaces(interfaces, typeVar.getBounds()); } } private static void addBoundInterfaces(List<Class<?>> interfaces, Type[] bounds) { for (Type bound : bounds) { addInterface(interfaces, bound); } } } }