mockit.internal.capturing.CaptureOfImplementations Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmockit Show documentation
Show all versions of jmockit Show documentation
JMockit is a Java toolkit for developer (unit/integration) testing.
It contains mocking APIs and other tools, supporting both JUnit and TestNG.
The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested
in isolation from selected dependencies.
/*
* 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.lang.reflect.*;
import java.util.*;
import org.jetbrains.annotations.*;
import mockit.external.asm4.*;
import mockit.external.asm4.Type;
import mockit.internal.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;
public abstract class CaptureOfImplementations implements Runnable
{
@NotNull private final List captureTransformers;
protected CaptureOfImplementations() { captureTransformers = new ArrayList(); }
@NotNull
protected abstract ClassVisitor createModifier(
@Nullable ClassLoader cl, @NotNull ClassReader cr, @NotNull String capturedTypeDesc);
public final void makeSureAllSubtypesAreModified(@NotNull Class> baseType)
{
makeSureAllSubtypesAreModified(baseType, false);
}
public final void makeSureAllSubtypesAreModified(@NotNull Class> baseType, boolean registerCapturedClasses)
{
if (baseType == TypeVariable.class) {
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(@NotNull CapturedType captureMetadata, @NotNull String baseTypeDesc)
{
Class>[] classesLoaded = Startup.instrumentation().getAllLoadedClasses();
for (Class> aClass : classesLoaded) {
if (captureMetadata.isToBeCaptured(aClass)) {
redefineClass(aClass, baseTypeDesc);
}
}
}
private void redefineClass(@NotNull Class> realClass, @NotNull 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(@NotNull 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(); }
}