All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
mockit.internal.expectations.mocking.BaseTypeRedefinition Maven / Gradle / Ivy
/*
* Copyright (c) 2006-2013 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.expectations.mocking;
import java.lang.instrument.*;
import java.lang.reflect.*;
import java.lang.reflect.Type;
import java.util.*;
import static java.lang.reflect.Modifier.*;
import mockit.external.asm4.*;
import mockit.internal.*;
import mockit.internal.expectations.mocking.InstanceFactory.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
abstract class BaseTypeRedefinition
{
private static final class MockedClass
{
final InstanceFactory instanceFactory;
final ClassDefinition[] mockedClassDefinitions;
MockedClass(InstanceFactory instanceFactory, ClassDefinition[] classDefinitions)
{
this.instanceFactory = instanceFactory;
mockedClassDefinitions = classDefinitions;
}
void redefineClasses()
{
RedefinitionEngine.redefineClasses(mockedClassDefinitions);
}
}
private static final Map mockedClasses = new HashMap();
private static final Map> mockInterfaces = new HashMap>();
Class targetClass;
MockedType typeMetadata;
InstanceFactory instanceFactory;
private List mockedClassDefinitions;
BaseTypeRedefinition(Class mockedType) { targetClass = mockedType; }
final InstanceFactory redefineType(Type typeToMock)
{
if (targetClass == null || targetClass.isInterface()) {
createMockedInterfaceImplementationAndInstanceFactory(typeToMock);
}
else {
redefineTargetClassAndCreateInstanceFactory(typeToMock);
}
TestRun.mockFixture().registerInstanceFactoryForMockedType(targetClass, instanceFactory);
return instanceFactory;
}
private void createMockedInterfaceImplementationAndInstanceFactory(Type interfaceToMock)
{
Class mockedInterface = interfaceToMock(interfaceToMock);
if (mockedInterface == null) {
createMockInterfaceImplementationUsingStandardProxy(interfaceToMock);
return;
}
Class mockClass = mockInterfaces.get(interfaceToMock);
if (mockClass != null) {
targetClass = mockClass;
createNewMockInstanceFactoryForInterface();
return;
}
generateNewMockImplementationClassForInterface(interfaceToMock);
createNewMockInstanceFactoryForInterface();
mockInterfaces.put(interfaceToMock, targetClass);
}
private Class interfaceToMock(Type typeToMock)
{
if (typeToMock instanceof Class) {
Class theInterface = (Class) typeToMock;
if (isPublic(theInterface.getModifiers()) && !theInterface.isAnnotation()) {
return theInterface;
}
}
else if (typeToMock instanceof ParameterizedType) {
return interfaceToMock(((ParameterizedType) typeToMock).getRawType());
}
return null;
}
private void createMockInterfaceImplementationUsingStandardProxy(Type typeToMock)
{
Object mock = EmptyProxy.Impl.newEmptyProxy(getClass().getClassLoader(), typeToMock);
targetClass = mock.getClass();
redefineMethodsAndConstructorsInTargetType();
instanceFactory = new InterfaceInstanceFactory(mock);
}
private void createNewMockInstanceFactoryForInterface()
{
Object mock = ConstructorReflection.newInstanceUsingDefaultConstructor(targetClass);
instanceFactory = new InterfaceInstanceFactory(mock);
}
private void generateNewMockImplementationClassForInterface(final Type interfaceToMock)
{
targetClass = new ImplementationClass(interfaceToMock) {
@Override
protected ClassVisitor createMethodBodyGenerator(ClassReader typeReader, String className)
{
return new InterfaceImplementationGenerator(typeReader, interfaceToMock, className);
}
}.generateNewMockImplementationClassForInterface();
}
final void redefineMethodsAndConstructorsInTargetType()
{
redefineClassAndItsSuperClasses(targetClass, false);
}
private void redefineClassAndItsSuperClasses(Class realClass, boolean isSuperClass)
{
ClassReader classReader = createClassReader(realClass);
ExpectationsModifier modifier = createModifier(realClass, classReader);
if (isSuperClass) {
modifier.useDynamicMockingForSuperClass();
}
try {
redefineClass(realClass, classReader, modifier);
}
catch (VisitInterruptedException ignore) {
// As defined in ExpectationsModifier, some critical JRE classes have all methods excluded from mocking by
// default. This exception occurs when they are visited.
// In this case, we simply stop class redefinition for the rest of the class hierarchy.
return;
}
Class superClass = realClass.getSuperclass();
if (superClass != null && superClass != Object.class && superClass != Proxy.class && superClass != Enum.class) {
redefineClassAndItsSuperClasses(superClass, true);
}
}
abstract ExpectationsModifier createModifier(Class realClass, ClassReader classReader);
private void redefineClass(Class realClass, ClassReader classReader, ClassVisitor modifier)
{
classReader.accept(modifier, 0);
byte[] modifiedClass = modifier.toByteArray();
ClassDefinition classDefinition = new ClassDefinition(realClass, modifiedClass);
RedefinitionEngine.redefineClasses(classDefinition);
if (mockedClassDefinitions != null) {
mockedClassDefinitions.add(classDefinition);
}
}
private ClassReader createClassReader(Class realClass)
{
return ClassFile.createReaderOrGetFromCache(realClass);
}
private void redefineTargetClassAndCreateInstanceFactory(Type typeToMock)
{
Integer mockedClassId = redefineClassesFromCache();
if (mockedClassId == null) {
return;
}
if (targetClass.isEnum()) {
instanceFactory = new EnumInstanceFactory(targetClass);
redefineMethodsAndConstructorsInTargetType();
}
else if (isAbstract(targetClass.getModifiers())) {
redefineMethodsAndConstructorsInTargetType();
Class subclass = generateConcreteSubclassForAbstractType(typeToMock);
instanceFactory = new ClassInstanceFactory(subclass);
}
else {
redefineMethodsAndConstructorsInTargetType();
instanceFactory = new ClassInstanceFactory(targetClass);
}
storeRedefinedClassesInCache(mockedClassId);
}
final Integer redefineClassesFromCache()
{
Integer mockedClassId = typeMetadata != null ? typeMetadata.hashCode() : targetClass.hashCode();
MockedClass mockedClass = mockedClasses.get(mockedClassId);
if (mockedClass != null) {
mockedClass.redefineClasses();
instanceFactory = mockedClass.instanceFactory;
return null;
}
mockedClassDefinitions = new ArrayList();
return mockedClassId;
}
final void storeRedefinedClassesInCache(Integer mockedClassId)
{
ClassDefinition[] classDefs = mockedClassDefinitions.toArray(new ClassDefinition[mockedClassDefinitions.size()]);
MockedClass mockedClass = new MockedClass(instanceFactory, classDefs);
mockedClasses.put(mockedClassId, mockedClass);
}
private Class generateConcreteSubclassForAbstractType(Type typeToMock)
{
String subclassName = getNameForConcreteSubclassToCreate();
ClassReader classReader = createClassReader(targetClass);
SubclassGenerationModifier modifier =
new SubclassGenerationModifier(typeMetadata.mockingCfg, typeToMock, classReader, subclassName);
classReader.accept(modifier, 0);
return new ImplementationClass().defineNewClass(targetClass.getClassLoader(), modifier, subclassName);
}
abstract String getNameForConcreteSubclassToCreate();
}