问题描述
我想转换对象的每个 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);
到目前为止,一切正常,如果我执行此操作,则所有字符串值最后都会附加“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>>
1楼
ArrayList
包含一个long
serialVersionUID
字段以帮助序列化。
当您获得该值时,它会返回一个装箱的Long
。
在Long
上调用getDeclaredFields
返回一个包含Long.MIN_VALUE
字段的数组,它是一个Long
。
这就是无限循环的由来。
为了解决这个问题,我会像你对Integer
一样为Long
添加特殊情况处理。
您还应该考虑所有其他盒装原语,如Float
和Byte
。
集合将由相互引用链接LinkedList
或由数组支持。
对于链接结构,代码将遍历它们。
要支持数组支持收集,您需要确定哪些字段是数组并遍历它们。
字段的类型,可通过。
数组可以通过来标识。
不同类型的数组具有不同的类型,它们不像 Java 泛型那样是非具体化的。
非原始值的数组可以转换为Object[]
,这在这种情况下很有用,但它。
可以使用来获取数组中对象的类型。
需要像下面这样的东西来递归数组的条目。
final Class<?> fieldType = field.getType();
if (fieldType.isArray() && !fieldType.getComponentType().isPrimitive()) {
Object[] fs = (Object[]) f;
for (Object fi : fs) {
reflect(fi);
}
}
另一个问题是循环引用可能导致进一步的StackOverflowException
。
如果将列表作为成员添加到自身,它将无限递归。
有必要跟踪以前访问过的对象,而不是两次访问它们。
理想情况下,这将使用IdentityHashMap
因为您关心对象的实例而不是它们的相等性。