mockit.internal.classGeneration.BaseImplementationGenerator 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.classGeneration;
import java.util.*;
import javax.annotation.*;
import static java.lang.reflect.Modifier.*;
import mockit.external.asm.*;
import mockit.internal.*;
import mockit.internal.reflection.*;
import mockit.internal.reflection.GenericTypeReflection.*;
import static mockit.external.asm.Opcodes.*;
@SuppressWarnings("AbstractClassExtendsConcreteClass")
public abstract class BaseImplementationGenerator extends BaseClassModifier
{
private static final int CLASS_ACCESS = ACC_PUBLIC + ACC_FINAL;
@Nonnull private final List implementedMethods;
@Nonnull private final String implementationClassDesc;
@Nullable private String[] initialSuperInterfaces;
protected String methodOwner;
protected BaseImplementationGenerator(@Nonnull ClassReader classReader, @Nonnull String implementationClassName)
{
super(classReader);
implementedMethods = new ArrayList();
implementationClassDesc = implementationClassName.replace('.', '/');
}
@Override
public void visit(
int version, int access, @Nonnull String name, @Nullable String signature, @Nullable String superName,
@Nullable String[] interfaces)
{
methodOwner = name;
initialSuperInterfaces = interfaces;
String[] implementedInterfaces = {name};
super.visit(version, CLASS_ACCESS, implementationClassDesc, signature, superName, implementedInterfaces);
generateNoArgsConstructor();
}
private void generateNoArgsConstructor()
{
mw = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
mw.visitVarInsn(ALOAD, 0);
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
generateEmptyImplementation();
}
@Override
public final AnnotationVisitor visitAnnotation(String desc, boolean visible) { return null; }
@Override
public final void visitInnerClass(String name, String outerName, String innerName, int access) {}
@Override
public final void visitOuterClass(String owner, @Nullable String name, @Nullable String desc) {}
@Override
public final void visitAttribute(Attribute attr) {}
@Override
public final void visitSource(@Nullable String source, @Nullable String debug) {}
@Nullable @Override
public final FieldVisitor visitField(
int access, String name, String desc, @Nullable String signature, @Nullable Object value)
{ return null; }
@Nullable @Override
public final MethodVisitor visitMethod(
int access, String name, String desc, @Nullable String signature, @Nullable String[] exceptions)
{
generateMethodImplementation(access, name, desc, signature, exceptions);
return null;
}
@Override
public final void visitEnd()
{
assert initialSuperInterfaces != null;
for (String superInterface : initialSuperInterfaces) {
new MethodGeneratorForImplementedSuperInterface(superInterface);
}
}
protected final void generateMethodImplementation(
int access, @Nonnull String name, @Nonnull String desc, @Nullable String signature, @Nullable String[] exceptions)
{
if (!isStatic(access)) {
String methodNameAndDesc = name + desc;
if (!implementedMethods.contains(methodNameAndDesc)) {
generateMethodBody(access, name, desc, signature, exceptions);
implementedMethods.add(methodNameAndDesc);
}
}
}
protected abstract void generateMethodBody(
int access, @Nonnull String name, @Nonnull String desc,
@Nullable String signature, @Nullable String[] exceptions);
protected final boolean isOverrideOfMethodFromSuperInterface(@Nonnull String name, @Nonnull String desc)
{
if (!implementedMethods.isEmpty()) {
int p = desc.lastIndexOf(')');
String descNoReturnType = desc.substring(0, p + 1);
for (String implementedMethod : implementedMethods) {
if (sameMethodName(implementedMethod, name) && implementedMethod.contains(descNoReturnType)) {
return true;
}
}
}
return false;
}
private static boolean sameMethodName(@Nonnull String implementedMethod, @Nonnull String name)
{
return implementedMethod.startsWith(name) && implementedMethod.charAt(name.length()) == '(';
}
@Nullable
protected final String getSubInterfaceOverride(
@Nonnull GenericTypeReflection genericTypeMap, @Nonnull String name, @Nonnull String genericSignature)
{
if (!implementedMethods.isEmpty()) {
GenericSignature parsedSignature = genericTypeMap.parseSignature(genericSignature);
for (String implementedMethod : implementedMethods) {
if (sameMethodName(implementedMethod, name) && parsedSignature.satisfiesSignature(implementedMethod)) {
return implementedMethod;
}
}
}
return null;
}
private final class MethodGeneratorForImplementedSuperInterface extends ClassVisitor
{
private String[] superInterfaces;
MethodGeneratorForImplementedSuperInterface(@Nonnull String interfaceName)
{
ClassFile.visitClass(interfaceName, this);
}
@Override
public void visit(
int version, int access, String name, @Nullable String signature, @Nullable String superName,
@Nullable String[] interfaces)
{
methodOwner = name;
superInterfaces = interfaces;
}
@Nullable @Override
public FieldVisitor visitField(
int access, String name, String desc, @Nullable String signature, @Nullable Object value)
{ return null; }
@Nullable @Override
public MethodVisitor visitMethod(
int access, String name, String desc, @Nullable String signature, @Nullable String[] exceptions)
{
generateMethodImplementation(access, name, desc, signature, exceptions);
return null;
}
@Override
public void visitEnd()
{
for (String superInterface : superInterfaces) {
new MethodGeneratorForImplementedSuperInterface(superInterface);
}
}
}
}