package com.googlecode.zohhak.internal.coercing;
import static com.googlecode.zohhak.internal.coercing.Result.FAILURE;
import java.lang.reflect.Type;
import java.util.List;
import org.apache.commons.lang3.ClassUtils;
import com.googlecode.zohhak.internal.model.SingleTestMethod;
/* start with string. add everything that starts from string.
* while true (not converted)
* check if we have matching tuple (if we reached tartgetType). generics?!
* if yes - try to use it without exception and result
* add everything that starts from the end of existing tuples and remove all tuples from that iteration (shortest)
* end of while
* throw coercion failed
*/
public class CoercingService {
private CoercionHandler coercionHandler = new CoercionHandler();
public Object[] coerceParameters(SingleTestMethod method, String[] splitedParameters) {
List<Coercion> methodCoercions = coercionHandler.findCoercionsForMethod(method);
int numberOfParams = method.getArity();
Object[] parameters = new Object[numberOfParams];
for (int i = 0; i < numberOfParams; i++) {
String inputString = splitedParameters[i];
Type parameterType = method.getParameterType(i);
parameters[i] = coerceParameter(parameterType, inputString, methodCoercions);
}
return parameters;
}
Object coerceParameter(Type type, String stringToParse, List<Coercion> methodCoercions) {
try {
if (stringToParse == null) {
return null;
}
if (type instanceof Class) {
Class<?> targetType = ClassUtils.primitiveToWrapper((Class<?>) type);
Result execution = tryToUseCoercions(targetType, stringToParse, methodCoercions);
if (execution.succeeded()) {
return execution.getResult();
}
if (targetType.isEnum()) {
return instantiateEnum(stringToParse, targetType);
}
}
} catch (RuntimeException e) {
throw new IllegalArgumentException(coercingExceptionMessage(stringToParse, type), e);
}
throw new IllegalArgumentException(coercingExceptionMessage(stringToParse, type));
}
private Result tryToUseCoercions(Class<?> targetType, String stringToParse, List<Coercion> methodCoercions) {
// TODO maybe index coercions by target type? will it be useful with future extended coercing?
for (Coercion coercion : methodCoercions) {
Result execution = tryToUseCoercion(coercion, targetType, stringToParse);
if (execution.succeeded()) {
return execution;
}
}
return FAILURE;
}
private Result tryToUseCoercion(Coercion coercion, Class<?> targetType, String stringToParse) {
if (targetType.isAssignableFrom(coercion.getTargetType())) {
return coercionHandler.invokeCoercion(coercion, stringToParse);
}
return FAILURE;
}
// unable to instantiate Enum from Class<?> without warnings
@SuppressWarnings({ "unchecked", "rawtypes" })
private Object instantiateEnum(String stringToParse, Class<?> targetType) {
return Enum.valueOf((Class) targetType, stringToParse);
}
private String coercingExceptionMessage(String stringToParse, Type targetType) {
return String.format("cannot interpret string \"%s\" as a %s", stringToParse, targetType);
}
}