Бесконечная рекурсия вложенных объектов

Я нашел несколько похожих потоков о бесконечном цикле при попытке сохранить объект как Json, но большинство из них относятся к java + jpa, и эти решения у меня не работают. Я хотел бы создать древовидную структуру некоторых данных. Есть класс ProjectNode, получивший

 private ArrayList<ProjectNode> children;

поле. Я почти уверен, что это одна из проблем, но это главное поле в этой структуре, я не могу его игнорировать. Я протестировал и могу преобразовать объект, который имеет список с узлом, у которого нет дочерних элементов, но не могу, если у какого-либо дочернего элемента есть другие дочерние элементы в приведенном ниже коде:

public class ProjectNode implements Comparable<ProjectNode>{
    private String parent;
    private String nodeName;
    private String nodeHref;
    private boolean hasChild;
    private int td;

    private ArrayList<ProjectNode> children;
    public ProjectNode() {
        super();
        // TODO Auto-generated constructor stub
    }

+ геттеры и сеттеры

ObjectMapper objectMapper = new ObjectMapper();

        String json = objectMapper.writeValueAsString(parser.getProjectFactory().get(12));

parser.getProjectFactory() возвращает список ParentNodes (parent = null), я хотел бы преобразовать 12 элементов, потому что есть случай, когда у узла есть дочерний элемент, а у этого дочернего элемента есть дочерний элемент. Причина этой ошибки:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"])
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:734)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)

Обновлено: Парсер - парсить список проектов / хостов из cacti:

    public List<ProjectNode> getProjectFactory() throws FailingHttpStatusCodeException, MalformedURLException, IOException {    
    FileWriter fstream = new FileWriter("graphMap.txt");
    BufferedWriter out = new BufferedWriter(fstream);
    String [] hostInfo = null;
    HtmlTableCell cel= (HtmlTableCell) page.getHtmlPage().getByXPath("/html/body/table/tbody/tr[5]/td[1]").get(0);
    System.out.println(cel.getChildElementCount());
    List<HtmlDivision> divs = cel.getByXPath(".//div");
    System.out.println(divs.size());
    //checks if list of host has been added to the project
    ProjectTree projectTree = new ProjectTree();
    Map<Integer,String> suppMap = new HashMap<Integer,String>();
    for(HtmlDivision div : divs) {

        List<DomNode> td = div.getByXPath(".//table/tbody/tr/td");
        if (td.size()>2) {

            ProjectNode pn = new ProjectNode(getNameSrc(td).split("@")[0],getNameSrc(td).split("@")[1],td.size());  

        hostInfo = getNameSrc(td).split("@");   
                if (pn.getTd()>3) {                      

                    if (!suppMap.get(pn.getTd()-1).isEmpty()) {
                        pn.setParent(suppMap.get(pn.getTd()-1));
                    }
                    if (suppMap.get(pn.getTd())!=null){
                        suppMap.remove(pn.getTd());                         
                    }
                    suppMap.put(pn.getTd(), pn.getNodeName());
                    projectTree.addNodeToTree(pn);

                } else {

                    projectTree.addNodeToTree(pn);

                    suppMap.put(pn.getTd(), pn.getNodeName());
                //out.write(pn.toString()+"\n");
                }
        }
    }
    ArrayList<ProjectNode> pns = projectTree.getNodeList();
    Collections.sort(pns, Comparator.comparing(ProjectNode::getTd)); 
    Collections.reverse(pns);
    projectTree.setNodeList(pns);
    List<ProjectNode> finalList = new ArrayList<ProjectNode>();
    for(ProjectNode pn :pns ) {
        if (pn.getTd()==3) {
            finalList.add(pn);
        }else {             
            projectTree.addToParent(pn);            
        }
    }
    Collections.reverse(finalList);
for(ProjectNode pn : finalList) {
    Collections.sort(pn.getChildren());

}
out.write(finalList.get(12).getChildren().get(4).getChildren().toString());
out.close();

    System.out.println(finalList.size());



    return finalList;
}

ProjectTree класс

public class ProjectTree {
    private ProjectNode rootNode;

private ArrayList<ProjectNode> NodeList;

public ProjectTree() {
        super();
        this.NodeList = new ArrayList<ProjectNode>();

}
public ProjectTree(ProjectNode rootNode, ArrayList<ProjectNode> nodeList) {
    super();
    this.rootNode = rootNode;
    NodeList = nodeList;
}


public ArrayList<ProjectNode> groupHosts(){

    return this.NodeList;
}

public void addToParent(ProjectNode pn) {
    for(ProjectNode pnA :this.NodeList) {
        if (pnA.getNodeName().equals(pn.getParent())) {
            if (pnA.getChildren()!=null && pnA.getChildren().size()!=0) {
                pnA.sortChildren();
            }
            pnA.addChlild(pn);
        }

    }
}

public ProjectNode getRootNode() {
    return rootNode;
}
public void setRootNode(ProjectNode rootNode) {
    this.rootNode = rootNode;
}
public ArrayList<ProjectNode> getNodeList() {
    return NodeList;
}
public void setNodeList(ArrayList<ProjectNode> nodeList) {
    NodeList = nodeList;
}


}

ProjectNode.class

public class ProjectNode implements Comparable<ProjectNode>{
    private String parent;
    private String nodeName;
    private String nodeHref;
    private boolean hasChild;
    private int td;

    private ArrayList<ProjectNode> children;
    public ProjectNode() {
        super();
        // TODO Auto-generated constructor stub
    }
    public ProjectNode( String nodeName, String nodeHref, int td) {
        super();

        this.nodeName = nodeName;
        this.nodeHref = nodeHref;
        this.hasChild =false;
        this.td=td;
    }
    public void addChlild(ProjectNode pn) {
        if (children!=null) {
            this.children.add(pn);
        }else {
            this.children = new ArrayList<ProjectNode>();
            this.children.add(pn);
        }
    }

    public List<ProjectNode> getChildren() {
        return children;
    }
    public void sortChildren() {
            Collections.sort(this.getChildren());;
        //Collections.sort(this.getChildren(), Comparator.comparing(ProjectNode::getNodeName)); 
            //System.out.println(this.children.toString());


    }
    public void setChildren(ArrayList<ProjectNode> children) {
        this.children = children;
    }
    public int getTd() {
        return td;
    }
    public void setTd(int td) {
        this.td = td;
    }
    public boolean isHasChild() {
        return hasChild;
    }
    public void setHasChild(boolean hasChild) {
        this.hasChild = hasChild;
    }
    public String getParent() {
        return parent;
    }
    public void setParent(String parent) {
        this.parent = parent;
    }
    public String getNodeName() {
        return nodeName;
    }
    public void setNodeName(String nodeName) {
        this.nodeName = nodeName;
    }
    public String getNodeHref() {
        return nodeHref;
    }
    public void setNodeHref(String nodeHref) {
        this.nodeHref = nodeHref;
    }
    @Override
    public String toString() {
        return "ProjectNode [parent = " + parent + ", nodeName = " + nodeName + ", nodeHref = " + nodeHref + ", hasChild = "
                + hasChild + ", td = " + td + ", children = "  +"]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((children == null) ? 0 : children.hashCode());
        result = prime * result + (hasChild ? 1231 : 1237);
        result = prime * result + ((nodeHref == null) ? 0 : nodeHref.hashCode());
        result = prime * result + ((nodeName == null) ? 0 : nodeName.hashCode());
        result = prime * result + ((parent == null) ? 0 : parent.hashCode());
        result = prime * result + td;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ProjectNode other = (ProjectNode) obj;
        if (children == null) {
            if (other.children != null)
                return false;
        } else if (!children.equals(other.children))
            return false;
        if (hasChild != other.hasChild)
            return false;
        if (nodeHref == null) {
            if (other.nodeHref != null)
                return false;
        } else if (!nodeHref.equals(other.nodeHref))
            return false;
        if (nodeName == null) {
            if (other.nodeName != null)
                return false;
        } else if (!nodeName.equals(other.nodeName))
            return false;
        if (parent == null) {
            if (other.parent != null)
                return false;
        } else if (!parent.equals(other.parent))
            return false;
        if (td != other.td)
            return false;
        return true;
    }
    @Override
    public int compareTo(ProjectNode o) {
        // TODO Auto-generated method stub
        return nodeName.compareTo(o.getNodeName());
    }





}

Я бы использовал рекурсию для группировки всех узлов в месте corect, но у меня была такая же ошибка (с stackoverflow), поэтому мне пришлось использовать работу, которая является функцией addToParent ().

Я не думаю, что проблема в частном массиве. Это может быть пустой массив, означающий, что у элемента нет дочернего элемента. Но, пожалуйста, не могли бы вы опубликовать еще код узла проекта? О каком парсере вы говорите?

Maurizio Ricci 01.09.2018 14:14

Ошибка могла быть в рекурсивной функции, опубликуйте ее

Maurizio Ricci 01.09.2018 14:15

Вы уверены, что в вашем «дереве» нет цикла?

Alexandre Dupriez 01.09.2018 14:17

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

Max Vollmer 01.09.2018 17:30

@MaxVollmer, я пробовал и ... Это сработало ... так что я думаю, мне нужно еще раз взглянуть на это и понять, где я все испортил

Hardodziob 01.09.2018 17:49

Возможно, вы захотите попробовать отладку «разделяй и властвуй». Это должно помочь вам быстро найти, в чем именно заключается проблема в вашем коде.

Max Vollmer 01.09.2018 18:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
690
1

Ответы 1

Я справился с этим, разорвав цикл, когда был найден родительский узел моего узла. Я сделал это просто для производительности, потому что раньше, даже если родительский цикл был найден, все равно проверял все элементы, поэтому я добавил break, и он работает .. Не знаю, почему .. Код ниже:

public void group() {

    int td = this.highestTd;
    while (td > 2) {

        List<ProjectNode> toRemove = new ArrayList<ProjectNode>();
        for (ProjectNode pnA : this.NodeList) {
            if (pnA.getTd()==3) {
                pnA.setParent("root");

            }
            if (pnA.getTd() == td) {

                for (ProjectNode pnB : this.NodeList) {
                    System.out.println(pnB.toString());

                    if (pnA.getParent()!=null && pnA.getParent().equals(pnB.getNodeName())) {

                        System.out.println("Dodaje "+pnA.getNodeName() + " Do "+pnB.getNodeName());
                        pnB.addChlild(pnA);

                        toRemove.add(pnA);
                        break;


                    }

                }

            }

        }
        td--;
        this.NodeList.removeAll(toRemove);
    }
}

Другие вопросы по теме