int generatedKeyColumnIndex = 1;
for (Field field : fields) {
DAOManaged daoManaged = field.getAnnotation(DAOManaged.class);
OrderBy orderBy = field.getAnnotation(OrderBy.class);
if (daoManaged != null) {
ReflectionUtils.fixFieldAccess(field);
if (field.isAnnotationPresent(OneToOne.class)) {
this.checkAutoGeneration(daoManaged);
// TODO Relation use this class pk, no extra field
// TODO check auto fields
throw new RuntimeException("OneToOne relations are not implemented yet!");
} else if (field.isAnnotationPresent(OneToMany.class)) {
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
this.checkOrderByAnnotation(field, orderBy);
if (field.getType() != List.class) {
throw new UnsupportedFieldTypeException("The annotated field " + field.getName() + " in " + beanClass + " is of unsupported type "
+ field.getType() + ". Fields annotated as @OneToMany have to be a genericly typed " + List.class, field, OneToMany.class,
beanClass);
}
if (ReflectionUtils.getGenericlyTypeCount(field) != 1) {
throw new UnsupportedFieldTypeException("The annotated field " + field.getName() + " in " + beanClass
+ " is genericly typed. Fields annotated as @OneToMany have to be a genericly typed " + List.class, field, OneToMany.class,
beanClass);
}
// This is a bit ugly but still necessary until someone else
// comes up with something smarter...
Class<?> remoteClass = (Class<?>) ReflectionUtils.getGenericType(field);
SimplifiedRelation simplifiedRelation = field.getAnnotation(SimplifiedRelation.class);
if (simplifiedRelation != null) {
this.oneToManyRelations.put(field, SimplifiedOneToManyRelation.getGenericInstance(beanClass, remoteClass, field, this, typePopulators, queryParameterPopulators));
} else {
// Use this class pks, no extra field
this.oneToManyRelations.put(field, DefaultOneToManyRelation.getGenericInstance(beanClass, remoteClass, field, daoFactory, daoManaged));
}
if (oneToMany.autoAdd()) {
this.autoAddRelations.add(field);
}
if (oneToMany.autoUpdate()) {
this.autoUpdateRelations.add(field);
}
if (oneToMany.autoGet()) {
this.autoGetRelations.add(field);
}
} else if (field.isAnnotationPresent(ManyToOne.class)) {
this.checkAutoGeneration(daoManaged);
ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
List<Field> remoteClassFields = ReflectionUtils.getFields(field.getType());
Field matchingRemoteField = null;
if (remoteClassFields != null) {
for (Field remoteField : remoteClassFields) {
if (remoteField.isAnnotationPresent(DAOManaged.class) && remoteField.isAnnotationPresent(OneToMany.class)
&& remoteField.getType() == List.class && ReflectionUtils.isGenericlyTyped(remoteField)
&& ((Class<?>) ReflectionUtils.getGenericType(remoteField) == this.beanClass)) {
matchingRemoteField = remoteField;
break;
}
}
}
if (matchingRemoteField == null) {
throw new RuntimeException("No corresponding @OneToMany annotated field found in " + field.getType()
+ " matching @ManyToOne relation of field " + field.getName() + " in " + beanClass + "!");
}
Field remoteKeyField = null;
if (!StringUtils.isEmpty(manyToOne.remoteKeyField())) {
remoteKeyField = ReflectionUtils.getField(field.getType(), manyToOne.remoteKeyField());
//TODO Check if the remote key field is @DAOPopluate annotated
if (remoteKeyField == null) {
throw new RuntimeException("Unable to find @Key annotated field " + manyToOne.remoteKeyField() + " in " + field.getType() + " specified for @ManyToOne annotated field "
+ field.getName() + " in " + beanClass);
}
} else {
for (Field remoteField : remoteClassFields) {
if (remoteField.isAnnotationPresent(DAOManaged.class) && remoteField.isAnnotationPresent(Key.class)) {
if (remoteKeyField != null) {
throw new RuntimeException("Found multiple @Key annotated fields in " + field.getType() + ", therefore the remoteKeyField property needs to be specified for the @ManyToOne annotated field "
+ field.getName() + " in " + beanClass);
}
remoteKeyField = remoteField;
}
}
if (remoteKeyField == null) {
throw new RuntimeException("Unable to find @Key annotated field in " + field.getType() + " while parsing @ManyToOne annotated field "
+ field.getName() + " in " + beanClass);
}
}
DefaultManyToOneRelation<T, ?, ?> relation = null;
if (field.isAnnotationPresent(Key.class)) {
relation = DefaultManyToOneRelation.getGenericInstance(beanClass, field.getType(), remoteKeyField.getType(), field, remoteKeyField, daoManaged, daoFactory);
manyToOneRelationKeys.put(field, relation);
} else {
relation = DefaultManyToOneRelation.getGenericInstance(beanClass, field.getType(), remoteKeyField.getType(), field, remoteKeyField, daoManaged, daoFactory);
this.manyToOneRelations.put(field, relation);
}
this.columnMap.put(field, relation);
if (orderBy != null) {
this.columnOrderMap.put(orderBy, relation);
}
if (manyToOne.autoAdd()) {
this.autoAddRelations.add(field);
}
if (manyToOne.autoUpdate()) {
this.autoUpdateRelations.add(field);
}
if (manyToOne.autoGet()) {
this.autoGetRelations.add(field);
}
} else if (field.isAnnotationPresent(ManyToMany.class)) {
this.checkAutoGeneration(daoManaged);
this.checkOrderByAnnotation(field, orderBy);
if (field.getType() != List.class) {
throw new UnsupportedFieldTypeException("The annotated field " + field.getName() + " in " + beanClass + " is of unsupported type "
+ field.getType() + ". Fields annotated as @ManyToMany have to be a genericly typed " + List.class, field, ManyToMany.class,
beanClass);
}
if (ReflectionUtils.getGenericlyTypeCount(field) != 1) {
throw new UnsupportedFieldTypeException("The annotated field " + field.getName() + " in " + beanClass
+ " is genericly typed. Fields annotated as @ManyToMany have to be a genericly typed " + List.class, field, ManyToMany.class,
beanClass);
}
// This is a bit ugly but still necessary until someone else
// comes up with something smarter...
Class<?> remoteClass = (Class<?>) ReflectionUtils.getGenericType(field);
this.manyToManyRelations.put(field, DefaultManyToManyRelation.getGenericInstance(beanClass, remoteClass, field, daoFactory, daoManaged));
ManyToMany manyToMany = field.getAnnotation(ManyToMany.class);
if (manyToMany.autoAdd()) {
this.autoAddRelations.add(field);
}
if (manyToMany.autoUpdate()) {
this.autoUpdateRelations.add(field);
}
if (manyToMany.autoGet()) {
this.autoGetRelations.add(field);
}
} else {
QueryParameterPopulator<?> queryPopulator = this.getQueryParameterPopulator(field.getType());
Method method = null;
if (queryPopulator == null) {
method = PreparedStatementQueryMethods.getQueryMethod(field.getType());
if (method == null && field.getType().isEnum()) {
queryPopulator = EnumPopulator.getInstanceFromField(field);
}
if (method == null && queryPopulator == null) {
throw new RuntimeException("No query method or query parameter populator found for @DAOManaged annotate field " + field.getName() + " in " + beanClass);
}
}
String columnName = daoManaged.columnName();
if (StringUtils.isEmpty(columnName)) {
columnName = field.getName();
}
SimpleColumn<T, ?> simpleColumn = null;
Key primaryKey = field.getAnnotation(Key.class);
if (primaryKey != null) {
simpleColumn = SimpleColumn.getGenericInstance(beanClass, field.getType(), field, method, queryPopulator, columnName, daoManaged
.autoGenerated());
this.simpleKeys.add(simpleColumn);
} else {
simpleColumn = SimpleColumn.getGenericInstance(beanClass, field.getType(), field, method, queryPopulator, columnName, daoManaged
.autoGenerated());
this.simpleColumns.add(simpleColumn);
}
this.columnMap.put(field, simpleColumn);
if (daoManaged.autoGenerated()) {
if (daoManaged.autGenerationColumnIndex() != 0) {
this.columnKeyCollectors.add(new ColumnKeyCollector<T>(field, populator, daoManaged.autGenerationColumnIndex()));
} else {
this.columnKeyCollectors.add(new ColumnKeyCollector<T>(field, populator, generatedKeyColumnIndex));