尝试使用反射检测 Java 中的循环引用

Trying to detect a circular reference in Java with reflection

我继承了一些遗留代码,如果存在循环引用,这些代码就会失败。该代码采用一个对象并构建整个对象图以转换为 XML。 遗留代码无法修改,所以我想检测引用并相应地处理它。

现在,我正在构建图中每个对象的所有字段的集合,然后 运行 通过每个对象字段并尝试检测对象是否相等。

这是构建 Set 的遗留代码部分。

// declaration of set for this instance
 Set<Object> noduplicates = new HashSet<Object>();


private Iterator<Field> findAllFields(Object o) {
    Collection<Field> result = new LinkedList<Field>();j
    Class<? extends Object> c = o.getClass();
    while (c != null) {
        Field[] f = c.getDeclaredFields();
        for (int i = 0; i < f.length; i++) {
            if (!Modifier.isStatic(f[i].getModifiers())) {
                result.add(f[i]);
            }
        }
        c = c.getSuperclass();
    }
// add the fields for each object, for later comparison
    noduplicates.addAll((Collection<?>) result);
    testForDuplicates(noduplicates)
}

这是目前检测圆度的尝试(灵感来自:):

private void testForDuplicates(Set<Object> noduplicates) throws ... {
    for (Object object : noduplicates) {
        Field[] fields = object.getClass().getFields();
        for (Field field : fields) {
            for (PropertyDescriptor pd : Introspector.getBeanInfo(field.getClass()).getPropertyDescriptors()) {
                  if (pd.getReadMethod() != null && !"class".equals(pd.getName())) {
                      Object possibleDuplicate = pd.getReadMethod().possibleDuplicate(object);
                      if (object.hashCode() == possibleDuplicate.hashCode()) {
                          System.out.println("Duplicated detected");
                          throw new RuntimeException();
                      }

                }
            }

        }
    }
}

我有一个非常简单的测试用例,两个 POJO,每个都引用了另一个:

class Prop {
    private Loc loc;

    public Loc getLoc() {
        return loc;
    }

    public void setLoc(Loc loc) {
        this.loc = loc;
    }
}

class Loc {
    private Prop prop;

    public Prop getProp() {
        return prop;
    }

    public void setProp(Prop prop) {
        this.prop = prop;
    }
}

我已经尝试了上述的几种变体,包括直接测试对象相等性。目前对哈希码相等性的测试从未检测到循环性。

不胜感激。

最后我自己想出来了。我在使用反射 API 时遇到的部分困惑是,例如,当您调用 Field.get(object);

object 必须是包含该字段的 class 的一个实例,这是有道理的,但不是立即直观的(至少对我来说不是)。

文档状态:

get(Object obj)
Returns the value of the field represented by this Field, on the specified object.

最后我想出的解决方案依赖于存储每个对象的 class 类型的映射,并使用它来确定它的任何字段是否引用它。

这就是我最终得到的结果:

 boolean testForDuplicates(Set<Object> noduplicates2) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, IntrospectionException {
    Map<Object, Object> duplicatesMap = new HashMap<Object, Object>();
    for (Object object : noduplicates2) {
        duplicatesMap.put(object.getClass(), object);
    }

    for (Object object : noduplicates2) {
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (duplicatesMap.containsKey(field.getType())) {
                Object possibleDupeFromField = duplicatesMap.get(field.getType());
                if (noduplicates2.contains(possibleDupeFromField)) {
                    return true;
                }
            }
        }
    }
    return false;
}

我会在有问题的真实代码中对其进行测试,如果发现任何其他问题,我会进行更新。