package jef.database.innerpool;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jef.accelerator.bean.BeanAccessor;
import jef.accelerator.bean.FastBeanWrapperImpl;
import jef.common.Entry;
import jef.database.IQueryableEntity;
import jef.database.jdbc.result.IResultSet;
import jef.database.wrapper.populator.IPopulator;
import jef.tools.FunctionProperty;
import jef.tools.reflect.BeanWrapper;
import jef.tools.reflect.GenericUtils;
import jef.tools.reflect.Property;
import com.google.common.base.Function;
public class NestedObjectPopulator implements IPopulator {
private String propertyName;
private InstancePopulator populator;
/**
* 为了提高性能而将部分拼装策略对象抽取出来进行缓存
*/
@SuppressWarnings("rawtypes")
private transient Class baseType;
private transient List<Entry<Property, BeanAccessor>> accessPath;
private transient Property lastAccessor;
public NestedObjectPopulator(String property, InstancePopulator populator) {
this.propertyName = property;
this.populator = populator;
}
private void parepare(Class<?> base) {
String name = propertyName;
int n = name.indexOf('.');
accessPath = new ArrayList<Entry<Property, BeanAccessor>>();
BeanAccessor ba = FastBeanWrapperImpl.getAccessorFor(base);
while (n > -1) {
String thisName = name.substring(0, n);
name = name.substring(n + 1);
n = name.indexOf('.');
Property accessor = ba.getProperty(thisName);
Class<?> accessorType = ba.getPropertyType(thisName);
ba = FastBeanWrapperImpl.getAccessorFor(accessorType);
accessPath.add(new Entry<Property, BeanAccessor>(accessor, ba));
}
lastAccessor = ba.getProperty(name);
checkAccessType();
baseType = base;
}
private void checkAccessType() {
Class<?> accessorType = lastAccessor.getType();
if (!accessorType.isAssignableFrom(populator.getObjectType())) {
if(accessorType==List.class || accessorType==ArrayList.class){
Type type=GenericUtils.getCollectionType(lastAccessor.getGenericType());
if(type==populator.getObjectType()){
this.lastAccessor=new FunctionProperty(lastAccessor).setSetFunction(new ToListFunction());
return;
}
}else if(accessorType==Set.class || accessorType==HashSet.class){
Type type=GenericUtils.getCollectionType(lastAccessor.getGenericType());
if(type==populator.getObjectType()){
this.lastAccessor=new FunctionProperty(lastAccessor).setSetFunction(new ToSetFunction());
return;
}
}
throw new IllegalArgumentException("Invalid config:" + accessorType.getName()+ " can not fill with " + populator.getObjectType().getName() + ".");
}
}
public void process(BeanWrapper wrapper, IResultSet rs) throws SQLException{
Object raw=wrapper.getWrapped();
if(raw.getClass()!=baseType){
parepare(raw.getClass());//初始化策略,在
}
Object subDo = populator.instance();
boolean flag = populator.processOrNull(BeanWrapper.wrap(subDo), rs);
if (flag) {
if (subDo instanceof IQueryableEntity) {
((IQueryableEntity) subDo).startUpdate();
}
for(Entry<Property,BeanAccessor> entry: accessPath){
Object v=entry.getKey().get(raw);
if(v==null){
v=entry.getValue().newInstance();
entry.getKey().set(raw, v);
}
raw=v;//构造中间对象
}
lastAccessor.set(raw, subDo);
}
}
@SuppressWarnings("rawtypes")
static class ToSetFunction implements Function<Object,Object>{
@SuppressWarnings("unchecked")
public Object apply(Object input) {
Set set=new HashSet();
set.add(input);
return set;
}
}
@SuppressWarnings("rawtypes")
static class ToListFunction implements Function<Object,Object>{
@SuppressWarnings("unchecked")
public Object apply(Object input) {
List list=new ArrayList();
list.add(input);
return list;
}
}
}