
mockit.internal.capturing.CaptureOfImplementations 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.capturing;
import java.util.*;
import mockit.external.asm4.*;
import mockit.internal.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;
public abstract class CaptureOfImplementations implements Runnable
{
private final List captureTransformers;
protected CaptureOfImplementations() { captureTransformers = new ArrayList(); }
protected abstract ClassVisitor createModifier(ClassLoader cl, ClassReader cr, String capturedTypeDesc);
public final void makeSureAllSubtypesAreModified(Class baseType)
{
makeSureAllSubtypesAreModified(baseType, false);
}
public final void makeSureAllSubtypesAreModified(Class baseType, boolean registerCapturedClasses)
{
if (baseType == null) {
throw new IllegalArgumentException("Capturing implementations of multiple base types is not supported");
}
String baseTypeDesc = Type.getInternalName(baseType);
CapturedType captureMetadata = new CapturedType(baseType);
redefineClassesAlreadyLoaded(captureMetadata, baseTypeDesc);
createCaptureTransformer(captureMetadata, registerCapturedClasses);
}
private void redefineClassesAlreadyLoaded(CapturedType captureMetadata, String baseTypeDesc)
{
Class[] classesLoaded = Startup.instrumentation().getAllLoadedClasses();
for (Class aClass : classesLoaded) {
if (captureMetadata.isToBeCaptured(aClass)) {
redefineClass(aClass, baseTypeDesc);
}
}
}
private void redefineClass(Class realClass, String baseTypeDesc)
{
if (!TestRun.mockFixture().containsRedefinedClass(realClass)) {
ClassReader classReader;
try {
classReader = ClassFile.createReaderOrGetFromCache(realClass);
}
catch (ClassFile.NotFoundException ignore) {
return;
}
ClassVisitor modifier = createModifier(realClass.getClassLoader(), classReader, baseTypeDesc);
classReader.accept(modifier, 0);
byte[] modifiedClass = modifier.toByteArray();
new RedefinitionEngine(realClass).redefineMethodsWhileRegisteringTheClass(modifiedClass);
}
}
private void createCaptureTransformer(CapturedType captureMetadata, boolean registerCapturedClasses)
{
CaptureTransformer transformer = new CaptureTransformer(captureMetadata, this, registerCapturedClasses);
Startup.instrumentation().addTransformer(transformer);
captureTransformers.add(transformer);
}
public void cleanUp()
{
for (CaptureTransformer transformer : captureTransformers) {
transformer.deactivate();
Startup.instrumentation().removeTransformer(transformer);
}
captureTransformers.clear();
}
public final void run() { cleanUp(); }
}