package se.unlogic.standardutils.populators.annotated;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import se.unlogic.standardutils.annotations.NoAnnotatedFieldsFoundException;
import se.unlogic.standardutils.annotations.UnsupportedFieldTypeException;
import se.unlogic.standardutils.dao.BeanResultSetPopulator;
import se.unlogic.standardutils.dao.ResultSetField;
import se.unlogic.standardutils.dao.annotations.DAOPopulate;
import se.unlogic.standardutils.dao.annotations.ManyToMany;
import se.unlogic.standardutils.dao.annotations.ManyToOne;
import se.unlogic.standardutils.dao.annotations.OneToMany;
import se.unlogic.standardutils.dao.annotations.OneToOne;
import se.unlogic.standardutils.populators.TypePopulator;
import se.unlogic.standardutils.reflection.ReflectionUtils;
import se.unlogic.standardutils.string.StringUtils;
public class AnnotatedResultSetPopulator<T> implements BeanResultSetPopulator<T>{
protected Class<T> beanClass;
protected ArrayList<ResultSetField> resultSetFields = new ArrayList<ResultSetField>();
public AnnotatedResultSetPopulator(Class<T> beanClass) throws UnsupportedFieldTypeException{
this(beanClass, (List<TypePopulator<?>>)null);
}
public AnnotatedResultSetPopulator(Class<T> beanClass, TypePopulator<?>... populators) throws UnsupportedFieldTypeException{
this(beanClass,Arrays.asList(populators));
}
@SuppressWarnings("unchecked")
public AnnotatedResultSetPopulator(Class<T> beanClass, List<TypePopulator<?>> populators) throws UnsupportedFieldTypeException{
this.beanClass = beanClass;
//cache fields
List<Field> fields = ReflectionUtils.getFields(beanClass);
for(Field field : fields){
DAOPopulate annotation = field.getAnnotation(DAOPopulate.class);
if(annotation != null && (!field.isAnnotationPresent(OneToOne.class) && !field.isAnnotationPresent(OneToMany.class) && !field.isAnnotationPresent(ManyToOne.class) && !field.isAnnotationPresent(ManyToMany.class) )){
if(Modifier.isFinal(field.getModifiers())){
throw new UnsupportedFieldTypeException("The annotated field " + field.getName() + " in class " + beanClass + " is final!", field, annotation.getClass(), beanClass);
}
Method resultSetMethod = ResultSetField.RESULTSET_METHODS.get(field.getType());
TypePopulator<?> typePopulator = null;
if(resultSetMethod == null){
if(populators != null){
typePopulator = this.getPopulator(populators, field, annotation);
}
if(typePopulator == null){
throw new UnsupportedFieldTypeException("The annotated field " + field.getName() + " in class " + beanClass + " is of unsupported type " + field.getType(), field, annotation.annotationType() , beanClass);
}
}
ReflectionUtils.fixFieldAccess(field);
if(!StringUtils.isEmpty(annotation.columnName())){
this.resultSetFields.add(new ResultSetField(field,resultSetMethod,annotation.columnName(),typePopulator));
}else{
this.resultSetFields.add(new ResultSetField(field,resultSetMethod,field.getName(),typePopulator));
}
}
}
if(this.resultSetFields.isEmpty()){
throw new NoAnnotatedFieldsFoundException(beanClass,DAOPopulate.class);
}
}
private TypePopulator<?> getPopulator(List<TypePopulator<?>> populators, Field field, DAOPopulate annotation) {
String populatorID = annotation.populatorID();
Object clazz = field.getType();
for(TypePopulator<?> populator : populators){
if(clazz.equals(populator.getType())){
if((StringUtils.isEmpty(populatorID) && populator.getPopulatorID() == null) || populatorID.equals(populator.getPopulatorID())){
return populator;
}
}
}
return null;
}
public T populate(ResultSet rs) throws SQLException, BeanResultSetPopulationException {
ResultSetField currentField = null;
try {
T bean = beanClass.newInstance();
for(ResultSetField resultSetField : this.resultSetFields){
currentField = resultSetField;
if(currentField.getResultSetMethod() != null){
Object value = resultSetField.getResultSetMethod().invoke(rs, resultSetField.getAlias());
if(rs.wasNull() && !resultSetField.getBeanField().getType().isPrimitive()){
resultSetField.getBeanField().set(bean, null);
}else{
resultSetField.getBeanField().set(bean, value);
}
}else{
String value = rs.getString(currentField.getAlias());
if(value != null || currentField.getTypePopulator().getType().isPrimitive()){
resultSetField.getBeanField().set(bean, currentField.getTypePopulator().getValue(value));
}else{
resultSetField.getBeanField().set(bean, null);
}
}
}
return bean;
} catch (InstantiationException e) {
throw new BeanResultSetPopulationException(currentField,e);
} catch (IllegalAccessException e) {
throw new BeanResultSetPopulationException(currentField,e);
} catch (IllegalArgumentException e) {
throw new BeanResultSetPopulationException(currentField,e);
} catch (InvocationTargetException e) {
throw new BeanResultSetPopulationException(currentField,e);
}
}
}