package org.test4j.datafilling;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import org.test4j.datafilling.annotations.FillWith;
import org.test4j.datafilling.common.AttributeInfo;
import org.test4j.datafilling.common.FillerHelper;
import org.test4j.datafilling.common.FillingConstants;
import org.test4j.datafilling.exceptions.PoJoFillException;
import org.test4j.datafilling.filler.ArrayFiller;
import org.test4j.datafilling.filler.CollectionFiller;
import org.test4j.datafilling.filler.EnumFiller;
import org.test4j.datafilling.filler.MapFiller;
import org.test4j.datafilling.filler.PoJoFiller;
import org.test4j.datafilling.filler.PrimitiveFiller;
import org.test4j.datafilling.filler.StringFiller;
import org.test4j.datafilling.strategy.AttributeStrategy;
import org.test4j.datafilling.strategy.DataFactory;
import org.test4j.datafilling.strategy.RandomDataFactory;
import org.test4j.module.core.utility.MessageHelper;
import org.test4j.tools.commons.ClazzHelper;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Filler {
protected DataFactory strategy;
protected Map<String, Type> argsTypeMap;
public Filler(DataFactory strategy, Map<String, Type> argsTypeMap) {
this.strategy = strategy;
this.argsTypeMap = argsTypeMap;
}
/**
* It retrieves the value for the {@link FillWith} annotation with which the
* attribute was annotated
*
* @param attributeType The attribute type, used for type checking
* @param attributeStrategy The {@link AttributeStrategy} to use
* @return The value for the {@link FillWith} annotation with which the
* attribute was annotated
* @throws Exception
*/
public Object returnAttributeDataStrategyValue(Class attributeType, AttributeStrategy attributeStrategy)
throws Exception {
try {
Method attributeStrategyMethod = attributeStrategy.getClass().getMethod(
FillingConstants.PoJoGen_ATTRIBUTE_STRATEGY_METHOD_NAME, new Class[] {});
if (!attributeType.isAssignableFrom(attributeStrategyMethod.getReturnType())) {
String errMsg = "The type of the Attribute Strategy is not " + attributeType.getName() + " but "
+ attributeStrategyMethod.getReturnType().getName() + ". An exception will be thrown.";
MessageHelper.error(errMsg);
throw new IllegalArgumentException(errMsg);
}
return attributeStrategy.getValue();
} catch (SecurityException e) {
throw new IllegalStateException(
"A security issue occurred while retrieving the Attribute Strategy details", e);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("It seems the Attribute Annotation is of the wrong type", e);
}
}
/**
* It manufactures and returns the value for a POJO attribute.
*
* @param attribute The type of the attribute for which a value is being
* manufactured
* @param typeArgsMap a map relating the generic class arguments ("<T, V>"
* for example) with their actual types
* @return The value for an attribute
* @throws Exception
*/
public <T> T fillingAttribute(AttributeInfo attribute) throws Exception {
if (attribute.isPrimitive()) {
return new PrimitiveFiller(strategy).fillingPrimitive(attribute);
} else if (attribute.isString()) {
return (T) new StringFiller(strategy).fillingString(attribute);
} else if (attribute.isArray()) {
return (T) new ArrayFiller(strategy, argsTypeMap).fillingArray(attribute);
} else if (attribute.isCollection()) {
return (T) new CollectionFiller(strategy, argsTypeMap).fillingCollection(attribute);
} else if (attribute.isMap()) {
return (T) new MapFiller(strategy, argsTypeMap).fillingMap(attribute);
} else if (attribute.isEnum()) {
return (T) new EnumFiller(strategy).fillingEnum(attribute);
} else {
return new PoJoFiller(strategy, argsTypeMap).fillingPoJo(attribute, 0);
}
}
public static <T> T filling(Class clazz, Type... genericTypeArgs) {
Object o = filling(RandomDataFactory.getInstance(), clazz, genericTypeArgs);
return (T) o;
}
public static <T> T filling(DataFactory strategy, FillUp fillUp) {
Class clazz = FillerHelper.getFillUpType(fillUp);
Type[] argsType = fillUp.getArgTypes();
Object o = filling(RandomDataFactory.getInstance(), clazz, argsType);
return (T) o;
}
public static <T> T filling(FillUp fillUp) {
Object o = filling(RandomDataFactory.getInstance(), fillUp);
return (T) o;
}
public static <T> T filling(DataFactory strategy, Class clazz, Type... genericTypeArgs) {
if (clazz.isInterface() || ClazzHelper.isAbstract(clazz)) {
MessageHelper.warn("Cannot instantiate an interface or abstract class. Returning null.");
return null;
}
AttributeInfo attribute = new AttributeInfo(clazz).setAttrArgs(genericTypeArgs);
Object o = filling(strategy, attribute);
return (T) o;
}
public static <T> T filling(DataFactory strategy, AttributeInfo attribute) {
try {
Object o = new Filler(strategy, new HashMap<String, Type>()).fillingAttribute(attribute);
return (T) o;
} catch (Exception e) {
throw new PoJoFillException(e.getMessage(), e);
}
}
}