package io.robe.hibernate.criteria.hql;
import io.robe.common.service.search.Relation;
import io.robe.common.service.search.SearchFrom;
import io.robe.common.service.search.SearchIgnore;
import io.robe.hibernate.criteria.api.cache.FieldReference;
import io.robe.hibernate.criteria.api.cache.EntityMeta;
import io.robe.hibernate.criteria.api.cache.EntityMetaFinder;
import io.robe.hibernate.criteria.api.cache.FieldMeta;
import javax.persistence.Id;
import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Predicate;
/**
* Created by kamilbukum on 12/01/2017.
*/
public class EntityMetaFinderImpl implements EntityMetaFinder {
/**
*
* @param entityClass
* @return
*/
@Override
public EntityMeta getEntityMeta(Class<?> entityClass) {
Map<String, FieldMeta> fieldMetaMap = new LinkedHashMap<>();
Map<String, String> relationMap = new LinkedHashMap<>();
String identityName = fillFieldMetaMap(entityClass, fieldMetaMap, relationMap);
return new EntityMeta(identityName, fieldMetaMap, relationMap);
}
/**
*
* @param type
* @param fieldMetaMap
* @return
*/
public static String fillFieldMetaMap(Class<?> type, Map<String, FieldMeta> fieldMetaMap, Map<String, String> relationMap) {
String identityName = null;
for(Field field: type.getDeclaredFields()) {
if(!ENTITY_FIELD_PREDICATE.test(field)) continue;
field.setAccessible(true);
Relation hasRelation = field.getAnnotation(Relation.class);
Transient isTransient = field.getAnnotation(Transient.class);
SearchIgnore ignore = field.getAnnotation(SearchIgnore.class);
SearchFrom searchFrom = field.getAnnotation(SearchFrom.class);
boolean collection = Collection.class.isAssignableFrom(field.getType());
FieldMeta meta;
if(searchFrom == null) { // this field hasn't any target
meta = new FieldMeta(field, isTransient != null,ignore != null, hasRelation != null, collection);
} else {
FieldReference reference = new FieldReference(
searchFrom.entity(),
searchFrom.select(),
searchFrom.filter(),
searchFrom.id(),
field.getName()
);
meta = new FieldMeta(field, reference, isTransient != null,ignore != null, hasRelation != null, collection);
}
fieldMetaMap.put(field.getName(), meta);
if(hasRelation != null) {
meta.setRelationName(hasRelation.name());
relationMap.put(hasRelation.name(), field.getName());
}
if(ENTITY_ID_FIELD_PREDICATE.test(field)) {
identityName = field.getName();
}
}
if(!type.getSuperclass().getName().equals(Object.class.getName())) {
String superIdentityName = fillFieldMetaMap(type.getSuperclass(), fieldMetaMap, relationMap);
if(identityName == null) {
identityName = superIdentityName;
}
}
return identityName;
}
private static final Predicate<Field> ENTITY_ID_FIELD_PREDICATE = (field) -> {
if(field.getAnnotation(Id.class) != null) return true;
return false;
};
private static final Predicate<Field> ENTITY_FIELD_PREDICATE = (field) -> {
if(field.isSynthetic()) return false;
if((field.getModifiers() & Modifier.STATIC) == Modifier.STATIC) return false;
if((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) return false;
return true;
};
}