![JAR search and dependency download from the Maven repository](/logo.png)
mockit.internal.state.CachedClassfiles 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.state;
import java.lang.instrument.*;
import java.security.*;
import java.util.*;
/**
* Holds a map of internal class names to the corresponding class files (bytecode arrays), for the classes
* that have already been loaded during the test run.
* These classfiles are not necessarily the same as those stored in the corresponding ".class" files
* available from the runtime classpath.
* If any third-party {@link java.lang.instrument.ClassFileTransformer}s are active, those original classfiles
* may have been modified before being loaded by the JVM.
* JMockit installs a {@code ClassFileTransformer} of its own which saves all potentially modified classfiles
* here.
*
* This bytecode cache allows classes to be mocked and un-mocked correctly, even in the presence of other
* bytecode modification agents such as the AspectJ load-time weaver.
*/
public final class CachedClassfiles implements ClassFileTransformer
{
public static final CachedClassfiles INSTANCE = new CachedClassfiles();
private final Map> classLoadersAndClassfiles =
new WeakHashMap>(2);
private ClassDefinition[] classesBeingMocked;
public void setClassesBeingMocked(ClassDefinition[] classDefs) { classesBeingMocked = classDefs; }
private CachedClassfiles() {}
public byte[] transform(
ClassLoader loader, String classDesc, Class> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer)
{
if (classBeingRedefined == null) { // class definition
if (!isExcluded(classDesc)) {
addClassfile(loader, classDesc, classfileBuffer);
}
}
else if (!isBeingMocked(classBeingRedefined) && !isExcluded(classDesc)) { // class redefinition
addClassfileIfNotYetPresent(loader, classDesc, classfileBuffer);
}
return null;
}
private boolean isExcluded(String classDesc)
{
return
classDesc.startsWith("org/junit/") ||
classDesc.startsWith("sun/") && !classDesc.startsWith("sun/proxy/$") ||
classDesc.startsWith("com/intellij/") ||
classDesc.startsWith("mockit/internal/") || classDesc.startsWith("mockit/integration/") ||
classDesc.startsWith("mockit/coverage/") ||
classDesc.startsWith("mockit/") && classDesc.indexOf('$') < 0;
}
private boolean isBeingMocked(Class> classBeingRedefined)
{
if (classesBeingMocked != null) {
for (ClassDefinition classDef : classesBeingMocked) {
if (classDef.getDefinitionClass() == classBeingRedefined) {
return true;
}
}
}
return false;
}
private synchronized void addClassfile(ClassLoader loader, String classDesc, byte[] classfile)
{
Map classfiles = getClassfiles(loader);
classfiles.put(classDesc, classfile);
}
private Map getClassfiles(ClassLoader loader)
{
Map classfiles = classLoadersAndClassfiles.get(loader);
if (classfiles == null) {
classfiles = new HashMap(100);
classLoadersAndClassfiles.put(loader, classfiles);
}
return classfiles;
}
private synchronized void addClassfileIfNotYetPresent(ClassLoader loader, String classDesc, byte[] classfile)
{
Map classfiles = getClassfiles(loader);
if (!classfiles.containsKey(classDesc)) {
classfiles.put(classDesc, classfile);
}
}
private synchronized byte[] findClassfile(Class> aClass)
{
Map classfiles = getClassfiles(aClass.getClassLoader());
return classfiles.get(aClass.getName().replace('.', '/'));
}
private synchronized byte[] findClassfile(ClassLoader loader, String classDesc)
{
Map classfiles = getClassfiles(loader);
return classfiles.get(classDesc);
}
public static byte[] getClassfile(Class> aClass) { return INSTANCE.findClassfile(aClass); }
public static byte[] getClassfile(ClassLoader loader, String internalClassName)
{
return INSTANCE.findClassfile(loader, internalClassName);
}
public static void addClassfile(Class> aClass, byte[] classfile)
{
INSTANCE.addClassfile(aClass.getClassLoader(), aClass.getName().replace('.', '/'), classfile);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy