io.hyperfoil.impl.ReflectionAcceptor Maven / Gradle / Ivy
package io.hyperfoil.impl;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
import io.hyperfoil.api.config.Visitor;
import io.hyperfoil.api.session.ReadAccess;
public class ReflectionAcceptor {
private static final Class>[] BOXING_TYPES = new Class[] {
Boolean.class, Integer.class, Long.class, Double.class, Byte.class, Character.class, Short.class, Float.class,
Void.class
};
public static int accept(Object target, Visitor visitor) {
int written = 0;
for (Field f : getAllFields(target)) {
if (f.getDeclaringClass().getModule() != ReflectionAcceptor.class.getModule()) {
// we have wandered astray
continue;
}
if (f.trySetAccessible()) {
try {
Visitor.Invoke invoke = f.getAnnotation(Visitor.Invoke.class);
if (invoke == null) {
Object value = f.get(target);
if (visitor.visit(f.getName(), value, f.getGenericType())) {
written++;
}
} else {
Method method = f.getDeclaringClass().getMethod(invoke.method());
method.setAccessible(true);
Object value = method.invoke(target);
if (visitor.visit(f.getName(), value, method.getGenericReturnType())) {
written++;
}
}
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
return written;
}
private static List getAllFields(Object target) {
Class> cls = target.getClass();
List fields = new ArrayList<>();
while (cls != null && cls != Object.class) {
for (Field f : cls.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()) || f.isSynthetic() || f.isAnnotationPresent(Visitor.Ignore.class)) {
// ignored fields
} else if ("parent".equals(f.getName())) {
// ignored as well
} else {
fields.add(f);
}
}
cls = cls.getSuperclass();
}
fields.sort(Comparator.comparing(Field::getName));
return fields;
}
public static boolean isScalar(Object value) {
if (value == null) {
return true;
}
if (value instanceof CharSequence || value instanceof ReadAccess) {
return true;
}
Class> cls = value.getClass();
// the superclass.isEnum is needed for enums with extra methods - these become non-enum somehow
return cls.isPrimitive() ||
cls.isEnum() || (cls.getSuperclass() != null && cls.getSuperclass().isEnum()) ||
Stream.of(BOXING_TYPES).anyMatch(c -> c == cls);
}
}