package org.test4j.json.decoder;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.test4j.json.JSON;
import org.test4j.json.JSONException;
import org.test4j.json.decoder.base.BaseDecoder;
import org.test4j.json.decoder.base.DecoderException;
import org.test4j.json.helper.JSONArray;
import org.test4j.json.helper.JSONMap;
import org.test4j.json.helper.JSONObject;
import org.test4j.tools.commons.ClazzHelper;
import org.test4j.tools.generic.GenericTypeFinder;
import org.test4j.tools.generic.GenericTypeMap;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CollectionDecoder extends BaseDecoder {
public static final CollectionDecoder toCOLLECTION = new CollectionDecoder();
@Override
public <T> T decode(JSONObject json, Type toType, Map<String, Object> references) {
if (json == null) {
return null;
}
if (json instanceof JSONMap) {
Collection list = this.parseFromJSONMap((JSONMap) json, toType, references);
return (T) list;
} else if (json instanceof JSONArray) {
Collection list = this.parseFromJSONArray(((JSONArray) json), toType, references);
return (T) list;
} else {
throw new DecoderException(
"illegal type for ArrayDecoder. the type can only is JSONArray or JSONMap, but actual is JSONSingle.");
}
}
private Collection parseFromJSONMap(JSONMap map, Type toType, Map<String, Object> references) {
String referenceID = map.getReferFromJSONProp();
if (referenceID != null) {
Object o = references.get(referenceID);
return (Collection) o;
}
Type type = map.getClazzFromJSONFProp(toType);
if (this.accept(type) == false) {
throw new JSONException("JSONMap must have property that declared the array type.");
}
JSONObject array = map.getValueFromJSONProp();
if (!(array instanceof JSONArray)) {
throw new JSONException("illegal type for ArrayDecoder. the type can only be JSONArray, but actual is "
+ array.getClass().getName());
}
Collection list = this.parseFromJSONArray(((JSONArray) array), toType, references);
String newID = map.getReferenceID();
if (newID != null) {
references.put(newID, list);
}
return list;
}
private final Collection parseFromJSONArray(JSONArray jsonArray, Type toType, Map<String, Object> references) {
Collection list = this.newInstance(toType);
for (Iterator<JSONObject> it = jsonArray.iterator(); it.hasNext();) {
JSONObject jsonObject = it.next();
Type componentType = getComponentType(toType);
Object o = JSON.toObject(jsonObject, componentType, references);
list.add(o);
}
return list;
}
private Type getComponentType(Type toType) {
GenericTypeMap typeMap = GenericTypeFinder.findGenericTypes(toType);
Type componentType = typeMap.getType(Collection.class, "E");
return componentType;
}
@Override
protected Collection newInstance(Type toType) {
Class raw = this.getRawType(toType, null);
Constructor constructor = null;
try {
constructor = raw.getConstructor();
} catch (Exception e) {
constructor = null;
}
if (constructor != null) {
Object o = ClazzHelper.newInstance(raw);
return (Collection) o;
} else {
return new ArrayList();
}
}
@Override
public boolean accept(Type type) {
Class raw = this.getRawType(type, null);
if (raw == null) {
return false;
} else {
return Collection.class.isAssignableFrom(raw);
}
}
}