目前我有几个嵌套类的类,如:
public class Foo {
private Bar bar;
//getter & setter
public class Bar {
private Abc abc;
//getter & setter
public class Abc {
@RequiredParam
private String property;
//getter & setter
}
}
}
我试图获得字段的价值,但我很难实现这个目标。
到目前为止,我有:
public static boolean isValid(Object paramClazz) throws Exception {
List<Class> classes = new ArrayList<>();
getClasses(classes, paramClazz.getClass());
for (Class clazz : classes) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(RequiredParam.class)) {
field.setAccessible(true);
//how to get the value? field.get(paramClazz) doesn't work
}
}
}
return true;
}
private static void getClasses(List<Class> classes, Class<?> clazz) {
if (clazz.getDeclaredClasses().length > 0) {
for (Class<?> c : clazz.getDeclaredClasses()) {
getClasses(classes, c);
}
}
classes.add(clazz);
}
我的目标是能够检查用@RequiredParam注释的字段是否为空,所以我有方法isValid()
,它将接收一个对象,并且应该能够检查所有字段(甚至是里面的字段)嵌套类)并查看是否有任何缺失。
问题是当我尝试拨打field.get()
并且我不知道我应该将哪个对象传递给此方法时。传递最高级别的对象不会起作用,因为我只需要以某种方式将Abc对象传递给方法。
我怎样才能将正确的对象传递给field.get()
调用,考虑到我的类中可以有更多或更少的嵌套级别?
答案 0 :(得分:3)
这是一个示例代码,它以递归方式扫描对象的所有字段,直到找到所有带注释字段的值:
public static Collection<Object> getAnnotatedValues(final Object root) throws ReflectiveOperationException {
return getAnnotatedValues(root, new HashSet<>());
}
private static Collection<Object> getAnnotatedValues(final Object root, final Set<Object> inspected)
throws ReflectiveOperationException {
final List<Object> annotatedValues = new ArrayList<>();
if (inspected.contains(root)) { // Prevents stack overflow.
return Collections.EMPTY_LIST;
}
inspected.add(root);
for (final Field field : gatherFields(root.getClass())) {
field.setAccessible(true);
final Object currentValue = field.get(root);
field.setAccessible(false);
if (field.isAnnotationPresent(RequiredParam.class)) {
// Found required value, search finished:
annotatedValues.add(currentValue);
if (currentValue != null) {
inspected.add(currentValue);
}
} else if (currentValue != null) {
// Searching for annotated fields in nested classes:
annotatedValues.addAll(getAnnotatedValues(currentValue, inspected));
}
}
return annotatedValues;
}
private static Iterable<Field> gatherFields(Class<?> fromClass) {
// Finds ALL fields, even the ones from super classes.
final List<Field> fields = new ArrayList<>();
while (fromClass != null) {
fields.addAll(Arrays.asList(fromClass.getDeclaredFields()));
fromClass = fromClass.getSuperclass();
}
return fields;
}
您可能已经实现了类似的功能,但无法访问最后一个嵌套类。这是因为Field
实例只是类的描述并且(除非该字段是静态的)它需要一个能够提取值的实际实例。来自Field#get(Object)
方法文档:
如果底层字段是静态字段,则忽略obj参数;它可能是空的。
否则,基础字段是实例字段。如果指定的obj参数为null,则该方法抛出NullPointerException。如果指定的对象不是声明基础字段的类或接口的实例,则该方法将抛出IllegalArgumentException。
如果你没有在类结构中启动字段,那么你很难提取一个值 - 即使你找到了注释字段,你仍然需要一个类的实例来提取它们。例如,给定这些类:
public class Foo {
private final Bar bar = new Bar();
public class Bar {
private final Abc abc = new Abc();
public class Abc {
@RequiredParam private final String property = "Result.";
}
}
@Retention(RetentionPolicy.RUNTIME)
public static @interface RequiredParam {}
}
... getAnnotatedValues(new Foo())
返回包含"Result."
的集合。您可以轻松修改方法以满足您的需求(例如,一旦找到第一个有效的注释字段就返回true
,或者如果集合为空/只包含空值则返回false)。