mockit.internal.startup.InstrumentationHolder 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 automated developer testing.
It contains mocking/faking APIs and a code coverage tool, 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 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.startup;
import java.lang.instrument.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.jar.*;
public final class InstrumentationHolder implements Instrumentation
{
public static Instrumentation inst;
private static InstrumentationHolder wrappedInst;
public static String hostJREClassName;
@SuppressWarnings("unused")
public static void agentmain(String agentArgs, Instrumentation instrumentation)
{
set(instrumentation, null);
}
static void setHostJREClassName(String className)
{
hostJREClassName = className;
Class> regularHolderClass = getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader();
if (regularHolderClass != null) {
try {
Field field = getField(regularHolderClass, "hostJREClassName");
field.set(null, className);
}
catch (IllegalAccessException e) { throw new RuntimeException(e); }
}
}
private static Field getField(Class> aClass, String fieldName)
{
try { return aClass.getDeclaredField(fieldName); }
catch (NoSuchFieldException e) { throw new RuntimeException(e); }
}
public static InstrumentationHolder get()
{
if (inst == null) {
recoverInstrumentationFromHolderClassInSystemClassLoaderIfAvailable();
}
return wrappedInst;
}
private static void recoverInstrumentationFromHolderClassInSystemClassLoaderIfAvailable()
{
Class> regularHolderClass = getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader();
if (regularHolderClass != null) {
inst = readStaticField(regularHolderClass, "inst");
if (inst != null) {
hostJREClassName = readStaticField(regularHolderClass, "hostJREClassName");
invokeClearTransformersFromSystemCL(regularHolderClass);
wrappedInst = new InstrumentationHolder();
}
}
}
private static Class> getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader()
{
ClassLoader systemCL = ClassLoader.getSystemClassLoader();
if (InstrumentationHolder.class.getClassLoader() == systemCL) {
return null;
}
try { return Class.forName(InstrumentationHolder.class.getName(), true, systemCL); }
catch (ClassNotFoundException e) { return null; }
}
private static T readStaticField(Class> aClass, String fieldName)
{
Field field = getField(aClass, fieldName);
try {
@SuppressWarnings("unchecked") T value = (T) field.get(null);
return value;
}
catch (IllegalAccessException e) { throw new RuntimeException(e); }
}
private static void invokeClearTransformersFromSystemCL(Class> regularHolderClass)
{
try {
Method method = regularHolderClass.getDeclaredMethod("clearTransformers");
method.invoke(null);
}
catch (NoSuchMethodException e) { throw new RuntimeException(e); }
catch (IllegalAccessException e) { throw new RuntimeException(e); }
catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); }
}
public static void clearTransformers()
{
for (ClassFileTransformer transformer : transformers) {
inst.removeTransformer(transformer);
}
transformers.clear();
}
boolean wasRecreated() { return transformers.isEmpty(); }
static Instrumentation set(Instrumentation instrumentation, String hostJREClassName)
{
if (wrappedInst != null) {
clearTransformers();
}
inst = instrumentation;
wrappedInst = instrumentation == null ? null : new InstrumentationHolder();
InstrumentationHolder.hostJREClassName = hostJREClassName;
return wrappedInst;
}
public static List transformers;
private InstrumentationHolder()
{
Class> regularHolderClass = getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader();
if (regularHolderClass == null) {
transformers = new ArrayList();
}
else {
transformers = readStaticField(regularHolderClass, "transformers");
}
}
@Override
public void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
{
removePreviouslyAddedTransformersOfSameType(transformer);
inst.addTransformer(transformer, canRetransform);
transformers.add(transformer);
}
@Override
public void addTransformer(ClassFileTransformer transformer)
{
removePreviouslyAddedTransformersOfSameType(transformer);
inst.addTransformer(transformer);
transformers.add(transformer);
}
private void removePreviouslyAddedTransformersOfSameType(ClassFileTransformer transformer)
{
Class> transformerClass = transformer.getClass();
ClassLoader transformerCL = transformerClass.getClassLoader();
String transformerName = transformerClass.getName();
for (Iterator itr = transformers.iterator(); itr.hasNext(); ) {
ClassFileTransformer previouslyAdded = itr.next();
Class> previousTransformerClass = previouslyAdded.getClass();
if (
previousTransformerClass.getClassLoader() != transformerCL &&
previousTransformerClass.getName().equals(transformerName)
) {
inst.removeTransformer(previouslyAdded);
itr.remove();
}
}
}
@Override
public boolean removeTransformer(ClassFileTransformer transformer)
{
transformers.remove(transformer);
return inst.removeTransformer(transformer);
}
@Override
public void retransformClasses(Class>... classes) throws UnmodifiableClassException
{
inst.retransformClasses(classes);
}
@Override
public void redefineClasses(ClassDefinition... definitions)
throws ClassNotFoundException, UnmodifiableClassException
{
inst.redefineClasses(definitions);
}
@Override
public boolean isRetransformClassesSupported() { return true; }
@Override
public boolean isRedefineClassesSupported() { return true; }
@Override
public boolean isModifiableClass(Class> theClass) { return inst.isModifiableClass(theClass); }
@Override
public Class[] getAllLoadedClasses() { return inst.getAllLoadedClasses(); }
@Override
public Class[] getInitiatedClasses(ClassLoader loader) { return inst.getInitiatedClasses(loader); }
@Override
public long getObjectSize(Object objectToSize) { return inst.getObjectSize(objectToSize); }
@Override
public void appendToBootstrapClassLoaderSearch(JarFile jarfile) {}
@Override
public void appendToSystemClassLoaderSearch(JarFile jarfile) {}
@Override
public boolean isNativeMethodPrefixSupported() { return false; }
@Override
public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {}
}