Issue
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:
- 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());
}
}
Solution
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"
}
]
}
]
}
]
}
]
Answered By - Cleiton Freitas
Answer Checked By - Terry (JavaFixing Volunteer)