package org.finra.datagenerator.scaffolding.utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Created by dkopel on 6/28/16.
*/
public class ReflectionUtils {
public static <T extends Annotation> Collection<T> findAnnotation(Class<?> clazz, Class<T> annotation) {
Collection<T> collected = new HashSet();
if(clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
collected.addAll(findAnnotation(clazz.getSuperclass(), annotation));
} else {
for(T a : clazz.getAnnotationsByType(annotation)) {
collected.add(a);
}
for(Method m : clazz.getMethods()) {
for(T a : m.getAnnotationsByType(annotation)) {
collected.add(a);
}
}
for(Field f : clazz.getDeclaredFields()) {
for(T a : f.getAnnotationsByType(annotation)) {
collected.add(a);
}
}
}
return collected;
}
public static <T extends Annotation> Collection<AnnotationAssociation<T>> findAnnotationsWithAssociation(Class<?> clazz, Class<T> annotation) {
Collection<AnnotationAssociation<T>> collected = new HashSet();
if(clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
collected.addAll(findAnnotationsWithAssociation(clazz.getSuperclass(), annotation));
} else {
for(T a : clazz.getAnnotationsByType(annotation)) {
collected.add(new AnnotationAssociation<T>(a).addAssociation(clazz));
}
for(Method m : clazz.getMethods()) {
for(T a : m.getAnnotationsByType(annotation)) {
collected.add(new AnnotationAssociation<T>(a).addAssociation(m));
}
}
for(Field f : clazz.getDeclaredFields()) {
for(T a : f.getAnnotationsByType(annotation)) {
collected.add(new AnnotationAssociation<T>(a).addAssociation(f));
}
}
}
return collected;
}
public static class AnnotationAssociation<T extends Annotation> {
private T annotation;
private Set<Object> associations = new HashSet();
public AnnotationAssociation(T annotation) {
this.annotation = annotation;
}
public AnnotationAssociation addAssociation(Class clazz) {
associations.add(clazz);
return this;
}
public AnnotationAssociation addAssociation(Method method) {
associations.add(method);
return this;
}
public AnnotationAssociation addAssociation(Field field) {
associations.add(field);
return this;
}
public T getAnnotation() {
return annotation;
}
public Set<Object> getAssociations() {
return associations;
}
}
public static Field getDeepProperty(Class<?> clazz, String fieldName) throws NoSuchFieldException {
Class<?> c = clazz;
while(c.getSuperclass() != null) {
List<Field> fields = Stream.of(c.getDeclaredFields())
.filter(f -> Objects.equals(f.getName(), fieldName))
.collect(Collectors.toList());
if(fields.size() == 1) {
return fields.get(0);
} else {
c = c.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
public static void setField(Field f, Object obj, Object val) throws IllegalAccessException {
boolean access = f.isAccessible();
f.setAccessible(true);
if(f.getType().equals(String.class) && val != null) {
val = val.toString();
}
f.set(obj, val);
f.setAccessible(access);
}
public static <T> T getFieldValue(Field f, Object obj) throws IllegalAccessException {
boolean access = f.isAccessible();
f.setAccessible(true);
T v = (T) f.get(obj);
f.setAccessible(access);
return v;
}
public static void copyField(Object from, Object to, String field) throws IllegalAccessException {
Class fc = from.getClass();
Class tc = to.getClass();
Field fOrg = org.springframework.util.ReflectionUtils.findField(fc, field);
Field fNew = org.springframework.util.ReflectionUtils.findField(tc, field);
boolean oaccess = fOrg.isAccessible();
fOrg.setAccessible(true);
Object value = fOrg.get(from);
fOrg.setAccessible(oaccess);
boolean naccess = fNew.isAccessible();
fNew.setAccessible(true);
fNew.set(to, value);
fNew.setAccessible(naccess);
}
}