我想转换对象的每个String属性(及其嵌套对象),并且我使用以下递归方法通过反射API来实现:
public static void reflect(Object obj) {
if (obj == null) {
return;
}
Class klazz = obj.getClass();
if (klazz.isPrimitive()
|| obj instanceof Integer
|| obj instanceof Double
|| obj instanceof Boolean)
return;
else {
try {
for (Field field : klazz.getDeclaredFields()) {
field.setAccessible(true);
Object f = field.get(obj);
if(f instanceof String) {
f = transform(f);
field.set(obj, f);
}
else {
reflect(f);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
private static Object transform(Object f) {
f = f + "blabla";
return f;
}
@Data
@Builder
public class PrintObject {
private String field1;
private String field2;
private String field3;
private NestedObject field4;
}
@Data
@Builder
public class NestedObject {
private String field1;
private String field2;
private Integer field3;
}
NestedObject nestedObject = NestedObject
.builder()
.field1("test")
.field2("test2")
.field3(1)
.build();
PrintObject printObject = PrintObject
.builder()
.field1("test")
.field2("Test")
.field3("test")
.field4(nestedObject)
.build();
Utils.reflect(printObject);
到目前为止,每个方法都可以正常工作,如果我执行此操作,则所有String值都将最后附加“ blabla”。 如果PrintObject具有其他数据结构(如List或Map),则会出现问题。 例如,如果PrintObject类中还有另一个字段:
private List<String> field5;
然后,此代码执行将引发StackOverflowError。
List<String> list = new ArrayList<>();
list.add("test");
NestedObject nestedObject = NestedObject
.builder()
.field1("test")
.field2("test2")
.field3(1)
.build();
PrintObject printObject = PrintObject
.builder()
.field1("test")
.field2("Test")
.field3("test")
.field4(nestedObject)
.field5(list)
.build();
Utils.reflect(printObject);
关于如何使这些结构也起作用的任何想法? 预先感谢。
field5也可以是例如:
Map<String,String>
甚至
List<List<String>>
答案 0 :(得分:1)
ArrayList
包含一个long
serialVersionUID
字段,以帮助进行序列化。当您获得该值时,它将返回一个带框的Long
。在getDeclaredFields
上调用Long
返回一个包含字段Long.MIN_VALUE
的数组,该字段是Long
。那就是无限循环的来源。
要解决此问题,我将像为Long
一样为Integer
添加特殊情况处理。您还应该考虑所有其他框式原语,例如Float
和Byte
。
将通过引用彼此链接LinkedList
的结构或数组来支持集合。对于链接结构,代码将遍历它们。为了支持收集的数组支持,您需要确定哪些字段是数组并对其进行迭代。
字段的类型,可通过Field.getType获得。数组可以用Class.isArray标识。不同类型的数组具有不同的类型,它们并非像Java泛型一样未经验证。可以将非基本值的数组强制转换为Object[]
,在这种情况下很有用,但它是not type safe。要获取数组Class.getComponentType中的对象类型,可以使用。
要对数组的条目进行递归,需要执行以下操作。
final Class<?> fieldType = field.getType();
if (fieldType.isArray() && !fieldType.getComponentType().isPrimitive()) {
Object[] fs = (Object[]) f;
for (Object fi : fs) {
reflect(fi);
}
}
另一个问题是循环引用,它可能进一步导致StackOverflowException
。如果将列表作为成员添加到其自身,它将无限递归。有必要跟踪以前访问过的对象,而不要两次访问它们。理想情况下,当您关心对象的实例而不是对象的相等性时,它将使用IdentityHashMap
。