package org.test4j.datafilling.filler;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.test4j.datafilling.Filler;
import org.test4j.datafilling.annotations.FillList;
import org.test4j.datafilling.common.AttributeInfo;
import org.test4j.datafilling.common.FillingConstants;
import org.test4j.datafilling.exceptions.PoJoFillException;
import org.test4j.datafilling.strategy.AttributeStrategy;
import org.test4j.datafilling.strategy.DataFactory;
import org.test4j.datafilling.strategy.EmptyStrategy;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CollectionFiller extends Filler {
public CollectionFiller(DataFactory strategy, Map<String, Type> argsTypeMap) {
super(strategy, argsTypeMap);
}
public Collection fillingCollection(AttributeInfo attribute) {
try {
Collection collInstance = createCollectionInstance(attribute);
AttributeInfo collItemAttribute = new AttributeInfo();
if (!attribute.isEmptyArgs()) {
collItemAttribute = AttributeInfo.exactArgAttributeInfo(attribute.getAttrArgs()[0], this.argsTypeMap);
}
fillCollection(collInstance, collItemAttribute.setAttrAnnotations(attribute.getAttrAnnotations()));
return collInstance;
} catch (Exception e) {
throw new PoJoFillException("An exception occurred while resolving the collection", e);
}
}
/**
* 根据PoJo属性创建Collection实例
*
* @return
*/
private Collection createCollectionInstance(AttributeInfo attribute) {
try {
Collection collInstance = attribute.getAttributeValue();
if (collInstance == null) {
throw new RuntimeException("create collection used attribute error!");
} else {
return collInstance;
}
} catch (Exception e) {
return createDefaultCollection(attribute.getAttrClaz());
}
}
/**
* Given a collection type it returns an instance
* <p>
* <ul>
* <li>The default type for a {@link List} is an {@link ArrayList}</li>
* <li>The default type for a {@link Queue} is a {@link LinkedList}</li>
* <li>The default type for a {@link Set} is a {@link HashSet}</li>
* </ul>
* </p>
*
* @param collectionType The collection type *
* @return an instance of the collection type
*/
public static Collection createDefaultCollection(Class collectionType) {
if (List.class.isAssignableFrom(collectionType) || collectionType.equals(Collection.class)) {
return new ArrayList();
} else if (Queue.class.isAssignableFrom(collectionType)) {
return new LinkedList();
} else if (Set.class.isAssignableFrom(collectionType)) {
return new HashSet();
} else {
throw new IllegalArgumentException("Collection type: " + collectionType + " not supported");
}
}
private FillList getFilling(AttributeInfo attrinbute) {
for (Annotation annotation : attrinbute.getAttrAnnotations()) {
if (FillList.class.isAssignableFrom(annotation.getClass())) {
FillList filling = (FillList) annotation;
return filling;
}
}
return null;
}
/**
* It fills a collection with the required number of elements of the
* required type.
* <p>
* This method has a so-called side effect. It updates the collection passed
* as argument.
* </p>
*
* @param collInstance The Collection to be filled
* @param collItemAttribute The type of the collection element and The
* generic type arguments for the current generic class instance
* @throws Exception
*/
public void fillCollection(Collection collInstance, AttributeInfo collItemAttribute) throws Exception {
FillList collectionAnnotation = this.getFilling(collItemAttribute);
AttributeStrategy elementStrategy = null;
int nbrElements = FillingConstants.ARRAY_DEFAULT_SIZE;
if (null != collectionAnnotation) {
nbrElements = collectionAnnotation.size();
elementStrategy = collectionAnnotation.collectionElementStrategy().newInstance();
}
for (int i = 0; i < nbrElements; i++) {
Object item = getCollctionItem(collItemAttribute, elementStrategy);
collInstance.add(item);
}
}
private Object getCollctionItem(AttributeInfo collItemAttribute, AttributeStrategy elementStrategy)
throws Exception {
if (null != elementStrategy && EmptyStrategy.class.isAssignableFrom(elementStrategy.getClass())
&& Object.class.equals(collItemAttribute.getAttrClaz())) {
return elementStrategy.getValue();
} else if (null != elementStrategy && !EmptyStrategy.class.isAssignableFrom(elementStrategy.getClass())) {
return returnAttributeDataStrategyValue(collItemAttribute.getAttrClaz(), elementStrategy);
} else {
return fillingAttribute(collItemAttribute);
}
}
}