I have two models that are having one to many relation (customers have many invoices) so i create one - many relation on it, this is my customer class :
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "serial_number")
private long serialNumber;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
@Column(name = "mobile_number")
private String mobileNumber;
@Column(name = "is_deleted")
private boolean isDeleted;
@OneToMany
private Set <Invoice> invoices;
}
and this is invoices class :
@Entity
@Table(name = "invoice")
public class Invoice {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "serial_number")
private long serialNumber;
@Column(name = "status")
private String status;
@Column(name = "created_date")
private Timestamp createdDate;
@Column(name = "is_deleted")
private boolean isDeleted;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
}
and then i create GET API ( get customers ) but it's nor working and return this error :
nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.invoices.model.Customer["invoices"]), path=/customer/viewList}]
and this is my api :
public List<Customer> getAllCustomers() {
List<Customer> customers = cutomerRepository.findAll();
return customers;
}
and controller :
@GetMapping("/viewList")
public ResponseEntity<List<Customer>> getAllCustomers() {
List<Customer> customers = new ArrayList<>();
customers = customerService.getAllCustomers();
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers, HttpStatus.OK);
}
CodePudding user response:
Do not open the entity class directly to the outside world
DTO use
for example
public class InvoiceDTO {
private int id;
private long serialNumber;
private String status;
private Timestamp createdDate;
private boolean isDeleted;
private CustomerDTO customer;
}
Apply see here:
https://github.com/musanabiyev/FurnitureStoreApplication/tree/main/src/main/java/com/company/dto
CodePudding user response:
You have a Bidirectional relation and therefore an endless loop if json tries to deserialize the Object.
You can use @JsonIgnore
to break the loop or use DTOs to return at the endpoint
@Entity
@Table(name = "invoice")
public class Invoice {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "serial_number")
private long serialNumber;
@Column(name = "status")
private String status;
@Column(name = "created_date")
private Timestamp createdDate;
@Column(name = "is_deleted")
private boolean isDeleted;
@ManyToOne
@JsonIgnore
@JoinColumn(name = "customer_id")
private Customer customer;
}
DTO would look something like this (I like to use records for this but since I don't know if you use Java 17 I still use class):
Customer:
@Data
public class CustomerDTO {
private int id;
private long serialNumber;
private String firstName;
private String lastName;
private String email;
private String mobileNumber;
private boolean isDeleted;
private Set <Invoice> invoices;
}
Invoice (here you don't show the customer again):
@Data
public class InvoiceDTO {
private int id;
private String status;
private Timestamp createdDate;
private boolean isDeleted;
}