2015-05-25 1 views
1

Я унаследовал какой-то старый код, который терпит неудачу, если есть круговая ссылка. Код принимает объект и строит весь граф объектов для преобразования в XML. Устаревший код не может быть изменен, поэтому я хочу определить ссылку и обработать ее соответствующим образом.Попытка обнаружить круговую ссылку в Java с отражением

В настоящее время я создаю набор всех полей для каждого объекта на графике, а затем проецирую через каждое поле объектов и пытаясь определить, равны ли эти объекты.

Это часть устаревшего кода, в котором установлен 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) 
} 

Это текущая попытка обнаружения округлости (вдохновленный: https://stackoverflow.com/a/2638662/817216):

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(); 
         } 

       } 
      } 

     } 
    } 
} 

У меня есть очень простой тестовый пример, два POJOs каждые со ссылкой на другую:

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; 
    } 
} 

Я пробовал несколько вариантов вышеизложенного, включая прямое тестирование равенства объектов. В настоящее время тестирование по равенству hashcode никогда не обнаруживает округлости.

Любые указатели с благодарностью получили.

+0

И что случилось с тем, что у вас сейчас есть? –

+0

Так что прямо сейчас, когда я пытаюсь обнаружить с помощью hashcode(), он не работает. Хотя я знаю, что там есть круговая ссылка (я отредактирую свой вопрос соответственно.) – eustachio

+0

Можете ли вы поделиться двумя POJO? –

ответ

0

Построил это сам в конце. Часть путаницы, с которой я столкнулся с использованием API Reflection, заключается в том, что, например, при вызове Field.get (object);

объект должен быть экземпляром класса, который содержит поле, что имеет смысл, но не сразу интуитивно (это было не для меня, по крайней мере).

Документы состояние:

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

В конце концов решения, которое я придумал полагается на хранение Карты типа класса каждого объекта, и с помощью, чтобы определить, есть ли какие-либо из его полей ссылаться на него.

Это то, что я закончил с:

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; 
} 

я проверить его в нарушившего реальном коде, и обновление, если я узнаю что-нибудь еще.