/*
* Copyright (c) 2006-2011 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.state;
import java.lang.reflect.*;
import java.util.*;
import mockit.external.asm.Type;
import mockit.internal.util.*;
public final class DefaultResults
{
private Map<String, ResultExtractor> defaultResults;
private static final class ResultExtractor
{
final Field inputField;
final Object fieldOwner;
volatile Object valueCache;
ResultExtractor(Field inputField, Object fieldOwner)
{
this.inputField = inputField;
this.fieldOwner = fieldOwner;
}
void extractException()
{
Object exception = getInputFieldValue();
Utilities.throwCheckedException((Exception) exception);
}
Object getInputFieldValue()
{
Object valueFromCache = valueCache;
if (valueFromCache != null) {
return valueFromCache;
}
Object fieldValue = Utilities.getFieldValue(inputField, fieldOwner);
if (fieldValue == null) {
fieldValue = Utilities.newInstanceUsingDefaultConstructor(inputField.getType());
}
valueCache = fieldValue;
return fieldValue;
}
}
public void add(Field inputField, Object fieldOwner)
{
Class<?> fieldType = inputField.getType();
String resultTypeDesc;
if (Exception.class.isAssignableFrom(fieldType)) {
resultTypeDesc = Type.getInternalName(fieldType);
}
else {
resultTypeDesc = getReturnTypeDescriptor(inputField, fieldType);
}
addExtractor(resultTypeDesc, new ResultExtractor(inputField, fieldOwner));
}
private String getReturnTypeDescriptor(Field inputField, Class<?> fieldType)
{
String returnTypeDesc = Utilities.invoke(Field.class, inputField, "getGenericSignature");
if (returnTypeDesc == null) {
returnTypeDesc = Type.getDescriptor(fieldType);
}
return returnTypeDesc;
}
private void addExtractor(String resultTypeDesc, ResultExtractor resultExtractor)
{
if (defaultResults == null) {
defaultResults = new HashMap<String, ResultExtractor>();
}
defaultResults.put(resultTypeDesc, resultExtractor);
}
public Object get(String signature, String[] exceptions)
{
if (defaultResults == null) {
return null;
}
ResultExtractor extractor;
if (exceptions != null) {
for (String exception : exceptions) {
extractor = defaultResults.get(exception);
if (extractor != null) {
extractor.extractException();
}
}
}
String returnTypeDesc = DefaultValues.getReturnTypeDesc(signature);
int typeParameter = returnTypeDesc.indexOf("<T");
extractor = typeParameter < 0 ? defaultResults.get(returnTypeDesc) : findResultForGenericType(typeParameter);
return extractor == null ? null : extractor.getInputFieldValue();
}
private ResultExtractor findResultForGenericType(int typeParamPos)
{
for (Map.Entry<String, ResultExtractor> keyAndValue : defaultResults.entrySet()) {
String key = keyAndValue.getKey();
if (key.length() > typeParamPos && key.charAt(typeParamPos) == '<' && key.indexOf(';', typeParamPos) > 0) {
return keyAndValue.getValue();
}
}
return null;
}
void clear()
{
defaultResults = null;
}
}