mockit.internal.ClassFile 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;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import javax.annotation.*;
import mockit.external.asm.*;
import mockit.internal.state.*;
import static mockit.external.asm.ClassReader.*;
public final class ClassFile
{
private static final Map CLASS_FILES = new ConcurrentHashMap();
private ClassFile() {}
public static final class NotFoundException extends RuntimeException
{
private NotFoundException(@Nonnull String classNameOrDesc)
{
super("Unable to find class file for " + classNameOrDesc.replace('/', '.'));
}
}
private static void verifyClassFileFound(@Nullable InputStream classFile, @Nonnull String classNameOrDesc)
{
if (classFile == null) {
throw new NotFoundException(classNameOrDesc);
}
}
@Nonnull
public static ClassReader createClassFileReader(@Nonnull Class> aClass)
{
byte[] cachedClassfile = CachedClassfiles.getClassfile(aClass);
if (cachedClassfile != null) {
return new ClassReader(cachedClassfile);
}
String className = aClass.getName();
InputStream classFile = aClass.getResourceAsStream('/' + className.replace('.', '/') + ".class");
verifyClassFileFound(classFile, className);
try {
return new ClassReader(classFile);
}
catch (IOException e) {
throw new RuntimeException("Failed to read class file for " + className, e);
}
}
@Nonnull
public static ClassReader createReaderOrGetFromCache(@Nonnull Class> aClass)
{
byte[] cachedClassfile = CachedClassfiles.getClassfile(aClass);
if (cachedClassfile != null) {
return new ClassReader(cachedClassfile);
}
String classDesc = aClass.getName().replace('.', '/');
ClassReader reader = CLASS_FILES.get(classDesc);
if (reader == null) {
reader = readFromFile(classDesc);
CLASS_FILES.put(classDesc, reader);
}
return reader;
}
@Nonnull @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
private static InputStream readClassFromClasspath(@Nonnull String classDesc)
{
String classFileName = classDesc + ".class";
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = null;
if (contextClassLoader != null) {
inputStream = contextClassLoader.getResourceAsStream(classFileName);
}
if (inputStream == null) {
ClassLoader thisClassLoader = ClassFile.class.getClassLoader();
if (thisClassLoader != contextClassLoader) {
inputStream = thisClassLoader.getResourceAsStream(classFileName);
if (inputStream == null) {
Class> testClass = TestRun.getCurrentTestClass();
if (testClass != null) {
inputStream = testClass.getClassLoader().getResourceAsStream(classFileName);
}
}
}
}
verifyClassFileFound(inputStream, classDesc);
//noinspection ConstantConditions
return inputStream;
}
@Nonnull
public static ClassReader createReaderFromLastRedefinitionIfAny(@Nonnull Class> aClass)
{
byte[] classfile = TestRun.mockFixture().getRedefinedClassfile(aClass);
if (classfile == null) {
classfile = CachedClassfiles.getClassfile(aClass);
}
if (classfile != null) {
return new ClassReader(classfile);
}
String classDesc = aClass.getName().replace('.', '/');
ClassReader reader = readFromFile(classDesc);
CLASS_FILES.put(classDesc, reader);
return reader;
}
@Nonnull
public static ClassReader createClassFileReader(@Nullable ClassLoader loader, @Nonnull String internalClassName)
{
byte[] cachedClassfile = CachedClassfiles.getClassfile(loader, internalClassName);
if (cachedClassfile != null) {
return new ClassReader(cachedClassfile);
}
return readFromFile(internalClassName);
}
@Nonnull
public static ClassReader readFromFile(@Nonnull Class> aClass)
{
String classDesc = aClass.getName().replace('.', '/');
return readFromFile(classDesc);
}
@Nonnull
public static ClassReader readFromFile(@Nonnull String classDesc)
{
if (classDesc.startsWith("java/") || classDesc.startsWith("javax/")) {
byte[] classfile = CachedClassfiles.getClassfile(classDesc);
if (classfile != null) {
return new ClassReader(classfile);
}
}
InputStream classFile = readClassFromClasspath(classDesc);
try {
return new ClassReader(classFile);
}
catch (IOException e) {
throw new RuntimeException("Failed to read class file for " + classDesc.replace('/', '.'), e);
}
}
public static void visitClass(@Nonnull String classDesc, @Nonnull ClassVisitor visitor)
{
byte[] classfile = CachedClassfiles.getClassfile(classDesc);
ClassReader cr = classfile != null ? new ClassReader(classfile) : readFromFile(classDesc);
cr.accept(visitor, SKIP_DEBUG + SKIP_FRAMES);
}
}