Create node sequence in tree list

Viewed 27

I need to add sequence of nodes in a tree response. Can you tell me how to implement this?

Below is the current answer and the answer I hope to get with your help!

Current response:

[
    {
        "id": 1,
        "node": null,
        "name": "Step1 - record 1",
        "step2": [
            {
                "id": 1,
                "node": null,
                "name": "Step2 - record 1",
                "step3": [
                    {
                        "id": 1,
                        "node": null,
                        "name": "Step3 - record 1",
                        "step4": [
                            {
                                "id": 1,
                                "node": null,
                                "name": "Step4 - record 1"
                            }
                        ]
                    }
                ]
            },
            {
                "id": 2,
                "node": null,
                "name": "Step2 - record 2",
                "step3": [
                    {
                        "id": 2,
                        "node": null,
                        "name": "Step3 - record 2",
                        "step4": [
                            {
                                "id": 2,
                                "node": null,
                                "name": "Step4 - record 2"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "node": null,
        "name": "Step1 - record 2",
        "step2": [
            {
                "id": 3,
                "node": null,
                "name": "Step2 - record 3",
                "step3": [
                    {
                        "id": 3,
                        "node": null,
                        "name": "Step3 - record 3",
                        "step4": [
                            {
                                "id": 3,
                                "node": null,
                                "name": "Step4 - record 3"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

Expected response:

[
    {
        "id": 1,
        "node": 1,
        "name": "Step1 - record 1",
        "step2": [
            {
                "id": 1,
                "node": 3,
                "name": "Step2 - record 1",
                "step3": [
                    {
                        "id": 1,
                        "node": 6,
                        "name": "Step3 - record 1",
                        "step4": [
                            {
                                "id": 1,
                                "node": 9,
                                "name": "Step4 - record 1"
                            }
                        ]
                    }
                ]
            },
            {
                "id": 2,
                "node": 4,
                "name": "Step2 - record 2",
                "step3": [
                    {
                        "id": 2,
                        "node": 7,
                        "name": "Step3 - record 2",
                        "step4": [
                            {
                                "id": 2,
                                "node": 10,
                                "name": "Step4 - record 2"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "node": 2,
        "name": "Step1 - record 2",
        "step2": [
            {
                "id": 3,
                "node": 5,
                "name": "Step2 - record 3",
                "step3": [
                    {
                        "id": 3,
                        "node": 8,
                        "name": "Step3 - record 3",
                        "step4": [
                            {
                                "id": 3,
                                "node": 11,
                                "name": "Step4 - record 3"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

I'm using the listTree method to generate the tree:

public List<Step1Dto> listTree(){
        var step1List = step1Rep.findAll().stream().map(Step1Dto::new)
                .collect(Collectors.toList());

        step1List.forEach(step1 -> {
            List<Step2Dto> step2List = step2Rep.findByStep1_Id(step1.getId()).stream().map(Step2Dto::new)
                    .collect(Collectors.toList());

            step2List.forEach(step2 -> {
                List<Step3Dto> step3List = step3Rep.findByStep2_Id(step2.getId()).stream().map(Step3Dto::new)
                        .collect(Collectors.toList());

                step3List.forEach(step3 -> {
                    List<Step4Dto> step4List = step4Rep.findByStep3_Id(step3.getId()).stream().map(Step4Dto::new)
                            .collect(Collectors.toList());

                    step3.setStep4(step4List);
                });
                step2.setStep3(step3List);
            });
            step1.setStep2(step2List);
        });

        return step1List;
    }

Requirements:

  1. Each node must have a unique number.

My classes:

MODEL

Step1

package com.example.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "step1")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Step1 {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @EqualsAndHashCode.Exclude
    @OneToMany(mappedBy = "step1",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY)
    @JsonManagedReference
    private List<Step2> step2 = new ArrayList<>();

}

Step2

package com.example.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "step2")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Step2 {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "step1_id", nullable = false, foreignKey = @ForeignKey(name = "fk_step2_step1"))
    private Step1 step1;

    private String name;

    @EqualsAndHashCode.Exclude
    @OneToMany(mappedBy = "step2",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY)
    @JsonManagedReference
    private List<Step3> step3 = new ArrayList<>();

}

Step3

package com.example.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "step3")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Step3 {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "step2_id", nullable = false, foreignKey = @ForeignKey(name = "fk_step3_step2"))
    private Step2 step2;

    private String name;

    @EqualsAndHashCode.Exclude
    @OneToMany(mappedBy = "step3",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY)
    @JsonManagedReference
    private List<Step4> step4 = new ArrayList<>();

}

Step4

package com.example.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "step4")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Step4 {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "step3_id", nullable = false, foreignKey = @ForeignKey(name = "fk_step4_step3"))
    private Step3 step3;

    private String name;

}

DTO

Step1Dto

package com.example.demo.dto;

import com.example.demo.model.Step1;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
public class Step1Dto {

    private Long id;
    private Long node;
    private String name;
    private List<Step2Dto> step2;

    public Step1Dto(Step1 step1) {
        this.id = step1.getId();
        this.name = step1.getName();
    }
}

Step2Dto

package com.example.demo.dto;

import com.example.demo.model.Step2;
import com.example.demo.model.Step3;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
public class Step2Dto {

    private Long id;
    private Long node;
    private String name;
    private List<Step3Dto> step3;

    public Step2Dto(Step2 step2) {
        this.id = step2.getId();
        this.name = step2.getName();
    }
}

Step3Dto

package com.example.demo.dto;

import com.example.demo.model.Step2;
import com.example.demo.model.Step3;
import com.example.demo.model.Step4;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
public class Step3Dto {

    private Long id;
    private Long node;
    private String name;
    private List<Step4Dto> step4;

    public Step3Dto(Step3 step3) {
        this.id = step3.getId();
        this.name = step3.getName();
    }
}

Step4Dto

package com.example.demo.dto;

import com.example.demo.model.Step3;
import com.example.demo.model.Step4;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
public class Step4Dto {

    private Long id;
    private Long node;
    private String name;

    public Step4Dto(Step4 step4) {
        this.id = step4.getId();
        this.name = step4.getName();
    }
}

REPOSITORY

Step1Rep

public interface Step1Rep extends JpaRepository<Step1, Long> {

}

Step2Rep

public interface Step2Rep extends JpaRepository<Step2, Long> {

    List<Step2> findByStep1_Id(long id);

}

Step3Rep

public interface Step3Rep extends JpaRepository<Step3, Long> {

    List<Step3> findByStep2_Id(long id);

}

Step4Rep

public interface Step4Rep extends JpaRepository<Step4, Long> {

    List<Step4> findByStep3_Id(long id);

}

SERVICE

StepService

package com.example.demo.service;

import com.example.demo.dto.Step1Dto;
import com.example.demo.dto.Step2Dto;
import com.example.demo.dto.Step3Dto;
import com.example.demo.dto.Step4Dto;
import com.example.demo.model.Step1;
import com.example.demo.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class StepService {

    private final Step1Rep step1Rep;
    private final Step2Rep step2Rep;
    private final Step3Rep step3Rep;
    private final Step4Rep step4Rep;

    public List<Step1> findAll() {
        return step1Rep.findAll();
    }

    public List<Step1Dto> listTree(){
        var step1List = step1Rep.findAll().stream().map(Step1Dto::new)
                .collect(Collectors.toList());

        step1List.forEach(step1 -> {
            List<Step2Dto> step2List = step2Rep.findByStep1_Id(step1.getId()).stream().map(Step2Dto::new)
                    .collect(Collectors.toList());

            step2List.forEach(step2 -> {
                List<Step3Dto> step3List = step3Rep.findByStep2_Id(step2.getId()).stream().map(Step3Dto::new)
                        .collect(Collectors.toList());

                step3List.forEach(step3 -> {
                    List<Step4Dto> step4List = step4Rep.findByStep3_Id(step3.getId()).stream().map(Step4Dto::new)
                            .collect(Collectors.toList());

                    step3.setStep4(step4List);
                });
                step2.setStep3(step3List);
            });
            step1.setStep2(step2List);
        });

        return step1List;
    }

}

CONTROLLER

StepController

package com.example.demo.controller;

import com.example.demo.dto.Step1Dto;
import com.example.demo.service.StepService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("api/v1/step")
@RequiredArgsConstructor
public class StepController {

    private final StepService stepService;

    @GetMapping("/tree")
    public ResponseEntity<List<Step1Dto>> listTree() {
        return ResponseEntity.ok(stepService.listTree());
    }


}
1 Answers

I managed to solve it by adding a node variable and incrementing it inside the forEach.

public List<Step1Dto> listTree() {
        var step1List = step1Rep.findAll().stream().map(Step1Dto::new)
                .collect(Collectors.toList());

        AtomicLong node = new AtomicLong();

        step1List.forEach(step1 -> {
            List<Step2Dto> step2List = step2Rep.findByStep1_Id(step1.getId()).stream().map(Step2Dto::new)
                    .collect(Collectors.toList());

            step2List.forEach(step2 -> {
                List<Step3Dto> step3List = step3Rep.findByStep2_Id(step2.getId()).stream().map(Step3Dto::new)
                        .collect(Collectors.toList());

                step3List.forEach(step3 -> {
                    List<Step4Dto> step4List = step4Rep.findByStep3_Id(step3.getId()).stream().map(Step4Dto::new)
                            .collect(Collectors.toList());

                    step4List.forEach(step4 -> {
                        node.getAndIncrement();
                        step4.setNode(node.longValue());
                    });

                    step3.setStep4(step4List);
                    node.getAndIncrement();
                    step3.setNode(node.longValue());
                });
                step2.setStep3(step3List);
                node.getAndIncrement();
                step2.setNode(node.longValue());
            });
            step1.setStep2(step2List);
            node.getAndIncrement();
            step1.setNode(node.longValue());
        });

        return step1List;
    }

Response

[
    {
        "id": 1,
        "node": 7,
        "name": "Step1 - record 1",
        "step2": [
            {
                "id": 1,
                "node": 3,
                "name": "Step2 - record 1",
                "step3": [
                    {
                        "id": 1,
                        "node": 2,
                        "name": "Step3 - record 1",
                        "step4": [
                            {
                                "id": 1,
                                "node": 1,
                                "name": "Step4 - record 1"
                            }
                        ]
                    }
                ]
            },
            {
                "id": 2,
                "node": 6,
                "name": "Step2 - record 2",
                "step3": [
                    {
                        "id": 2,
                        "node": 5,
                        "name": "Step3 - record 2",
                        "step4": [
                            {
                                "id": 2,
                                "node": 4,
                                "name": "Step4 - record 2"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "node": 11,
        "name": "Step1 - record 2",
        "step2": [
            {
                "id": 3,
                "node": 10,
                "name": "Step2 - record 3",
                "step3": [
                    {
                        "id": 3,
                        "node": 9,
                        "name": "Step3 - record 3",
                        "step4": [
                            {
                                "id": 3,
                                "node": 8,
                                "name": "Step4 - record 3"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]
Related