mockit.internal.expectations.mocking.MockedTypeModifier Maven / Gradle / Ivy
/*
* Copyright (c) 2006-2012 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.expectations.mocking;
import java.lang.reflect.*;
import java.lang.reflect.Type;
import mockit.external.asm4.*;
import mockit.internal.*;
import mockit.internal.util.*;
import static mockit.external.asm4.Opcodes.*;
class MockedTypeModifier extends BaseClassModifier
{
protected GenericTypeReflection genericTypeMap;
protected String implementationSignature;
protected MockedTypeModifier(ClassReader classReader, Type mockedType)
{
super(classReader);
if (mockedType != null) {
Class mockedClass = Utilities.getClassType(mockedType);
genericTypeMap = new GenericTypeReflection(mockedClass, mockedType);
implementationSignature = getGenericClassSignature(mockedType);
}
}
protected final String getGenericClassSignature(Type mockedType)
{
StringBuilder signature = new StringBuilder(100);
if (mockedType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) mockedType;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (typeArguments.length > 0) {
signature.append('<');
for (Type typeArg : typeArguments) {
if (typeArg instanceof Class) {
Class classArg = (Class) typeArg;
signature.append('L').append(classArg.getName().replace('.', '/')).append(';');
}
else {
signature.append('*');
}
}
signature.append('>');
}
}
signature.append(';');
return signature.toString();
}
protected final void generateDirectCallToHandler(
String className, int access, String name, String desc, String genericSignature, String[] exceptions,
int executionMode)
{
// First argument: the mock instance, if any.
boolean isStatic = generateCodeToPassThisOrNullIfStaticMethod(access);
// Second argument: method access flags.
mw.visitLdcInsn(access);
// Third argument: class name.
mw.visitLdcInsn(className);
// Fourth argument: method signature.
mw.visitLdcInsn(name + desc);
// Fifth argument: generic signature, or null if none.
generateInstructionToLoadNullableString(genericSignature);
// Sixth argument: checked exceptions thrown, or null if none.
String exceptionsStr = getListOfExceptionsAsSingleString(exceptions);
generateInstructionToLoadNullableString(exceptionsStr);
// Seventh argument: indicate regular or special modes of execution.
mw.visitLdcInsn(executionMode);
// Sixth argument: call arguments.
mockit.external.asm4.Type[] argTypes = mockit.external.asm4.Type.getArgumentTypes(desc);
generateCodeToPassMethodArgumentsAsVarargs(isStatic, argTypes);
mw.visitMethodInsn(
INVOKESTATIC, "mockit/internal/expectations/RecordAndReplayExecution", "recordOrReplay",
"(Ljava/lang/Object;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I" +
"[Ljava/lang/Object;)Ljava/lang/Object;");
}
private void generateInstructionToLoadNullableString(String text)
{
if (text == null) {
mw.visitInsn(ACONST_NULL);
}
else {
mw.visitLdcInsn(text);
}
}
private void generateCodeToPassMethodArgumentsAsVarargs(boolean isStatic, mockit.external.asm4.Type[] argTypes)
{
generateCodeToCreateArrayOfObject(argTypes.length);
generateCodeToPassMethodArgumentsAsVarargs(argTypes, 0, isStatic ? 0 : 1);
}
protected final String getListOfExceptionsAsSingleString(String[] exceptions)
{
if (exceptions == null) {
return null;
}
else if (exceptions.length == 1) {
return exceptions[0];
}
StringBuilder buf = new StringBuilder(200);
String sep = "";
for (String exception : exceptions) {
buf.append(sep).append(exception);
sep = " ";
}
return buf.toString();
}
protected final boolean isMethodFromObject(String name, String desc)
{
return
"equals".equals(name) && "(Ljava/lang/Object;)Z".equals(desc) ||
"hashCode".equals(name) && "()I".equals(desc) ||
"toString".equals(name) && "()Ljava/lang/String;".equals(desc) ||
"finalize".equals(name) && "()V".equals(desc);
}
}