/**
* Map of classes and classes and fields that contains the referenced class.
*/
private static Map<Class, Map<Class, List<Field>>> classReferences = new HashMap<>();
/**
* Determines a generic type of a field. For example: List<String> field should return String).
*/
public static Class getFieldGenericsType(Field field) {
if (field.getGenericType() instanceof ParameterizedType) {
ParameterizedType aType = (ParameterizedType) field.getGenericType();
Type[] fieldArgTypes = aType.getActualTypeArguments();
for (Type fieldArgType : fieldArgTypes) {
Class fieldArgClass = (Class) fieldArgType;
return fieldArgClass;
}
}
return null;
}
/**
* Gets all the declared fields of a given class.
**/
public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null) {
fields = getAllFields(fields, type.getSuperclass());
}
return fields;
}
/**
* Gets all the classes that referenced a given class.
*/
public static Map<Class, List<Field>> getReferencedClassesAndFieldsOfType(Class fieldClass) {
if (classReferences.containsKey(fieldClass)) {
return classReferences.get(fieldClass);
}
Class superClass = fieldClass.getSuperclass();
Map<Class, List<Field>> matchedFields = new HashMap<>();
Reflections reflections = new Reflections("com.broodcamp.model");
// gets all our entity classes in our project
Set<Class<? extends BaseEntity>> classes = reflections.getSubTypesOf(BaseEntity.class);
// loop thru
for (Class<? extends BaseEntity> clazz : classes) {
// we are not interested with either interface or abstract
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
// gets all the fields of a given class
List<Field> fields = getAllFields(new ArrayList<Field>(), clazz);
// loops thru the fields
for (Field field : fields) {
// we are not interested with transient field
if (field.isAnnotationPresent(Transient.class)) {
continue;
}
// filter the field or parametized field of type fieldClass
// this means it refer to our referenced class
if (field.getType() == fieldClass || (Collection.class.isAssignableFrom(field.getType()) && getFieldGenericsType(field) == fieldClass) || (superClass != null
&& (field.getType() == superClass || (Collection.class.isAssignableFrom(field.getType()) && getFieldGenericsType(field) == superClass)))) {
// add to map
if (!matchedFields.containsKey(clazz)) {
matchedFields.put(clazz, new ArrayList<>());
}
matchedFields.get(clazz).add(field);
}
}
}
classReferences.put(fieldClass, matchedFields);
return matchedFields;
}