package com.w11k.lsql.query;
import com.google.common.collect.Lists;
import com.w11k.lsql.PojoMapper;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public class PojoEntityCreator<T> extends EntityCreator {
private final Class<T> topLevelClass;
public PojoEntityCreator(Class<T> topLevelClass) {
this.topLevelClass = topLevelClass;
}
@SuppressWarnings("unchecked")
@Override
public Object createEntity(Object parent, String fieldNameInParent, boolean isList) {
if (parent == null) {
return PojoMapper.getFor(this.topLevelClass).newInstance();
}
PojoMapper<Object> parentPojoMapper = (PojoMapper<Object>) PojoMapper.getFor(parent.getClass());
Class<?> fieldTypeInParent = parentPojoMapper.getTypeOfField(fieldNameInParent);
PojoMapper<?> pojoMapper = PojoMapper.getFor(getTypeOfField(parent, fieldTypeInParent, fieldNameInParent, isList));
Object obj = pojoMapper.newInstance();
// Store entity in parent
Object fieldInParent = parentPojoMapper.getValue(parent, fieldNameInParent);
if (isList) {
// 1:n
Collection<Object> coll;
if (fieldInParent == null) {
coll = createCollectionInstance(fieldTypeInParent);
parentPojoMapper.setValue(parent, fieldNameInParent, coll);
} else {
coll = (Collection<Object>) fieldInParent;
}
coll.add(obj);
} else {
// 1:1
// TODO
// assert fieldInParent == null;
// parentRow.put(fieldNameInParent, row);
}
return obj;
}
@SuppressWarnings("unchecked")
@Override
public void setValue(Object entity, String fieldName, Object value) {
PojoMapper.getFor((Class<Object>) entity.getClass()).setValue(entity, fieldName, value);
}
private Collection<Object> createCollectionInstance(Class<?> fieldTypeInParent) {
if (fieldTypeInParent.equals(Collection.class)) {
return Lists.newLinkedList();
} else if (fieldTypeInParent.equals(List.class)) {
return Lists.newLinkedList();
} else if (fieldTypeInParent.equals(LinkedList.class)) {
return Lists.newLinkedList();
} else if (fieldTypeInParent.equals(ArrayList.class)) {
return Lists.newArrayList();
}
throw new RuntimeException("unsupported Collection field type: " + fieldTypeInParent.getCanonicalName());
}
@SuppressWarnings("unchecked")
private Class<?> getTypeOfField(Object parent, Class<?> fieldTypeInParent, String fieldNameInParent, boolean fieldExpectedToBeList) {
if (fieldExpectedToBeList && !Collection.class.isAssignableFrom(fieldTypeInParent)) {
throw new RuntimeException("field '" + fieldNameInParent + "' must be a subtype of " + Collection.class.getCanonicalName());
}
// direct field
if (!fieldExpectedToBeList) {
return fieldTypeInParent;
}
// List
try {
Field stringListField = parent.getClass().getDeclaredField(fieldNameInParent);
ParameterizedType listParamType = (ParameterizedType) stringListField.getGenericType();
return (Class<?>) listParamType.getActualTypeArguments()[0];
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
}