Jackson Infinite recursion while Serializing objects - spring

I have a Spring backend that sends a list to frontend in ReactJS, but it gives me StackOverflow error:
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:792) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.14.1.jar:2.14.1]
the classes are:
#Entity
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#Setter
#Getter
#SuperBuilder
public class Paziente extends UtenteRegistrato {
#OneToMany(mappedBy = "paziente",
fetch = FetchType.LAZY)
#JsonManagedReference
#JsonIgnore
private Set<DispositivoMedico> dispositivoMedico;
}
and
#Getter
#Setter
#Entity
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#Table(name = "Dispositivo_medico")
public class DispositivoMedico {
#ManyToOne
#JsonIgnore
#JoinColumn(name = "id_paziente",
referencedColumnName = "id")
#JsonBackReference
private Paziente paziente;
}
how can I fix this?

Related

How to implements entity with 2 entity as primary key with jpa annotation and repository

i want to implement a many to many association with quantity information in it . like this :
#Entity
#Table(name = "reserves")
#Getter #Setter #NoArgsConstructor
public class Reserve {
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "groupe_id")
private GroupeSanguin bloodGroup;
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Banque banque;
private int quantity;
}
the GroupSanguin and the Banque are two class stored in the database two . here is the code for the two if you need :
#Entity
#Table(name = "groupe_sanguins")
public class GroupeSanguin {
#Id
private String groupe;
#OneToMany(mappedBy = "groupeSanguin")
private List<Donneur> donneurs;
}
#Entity #Getter #Setter #NoArgsConstructor
public class Banque {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true,nullable = false)
private String nom;
private String adresse;
#Column(unique = true)
private String telephone;
private String localisation;
}
so my i want to know how to annotate the JpaRepository to take the two as primary key like this and is my annotation good for it to work ?
public interface ReserveRepository extends JpaRepository<
Reserve,
//what to put here ?
>
This isn't a JPA question in fact, it's a relationnal database conception.
If Reserve has is own data and links with other entity it has it own Id
You can add unicity constraint
#Entity
#Table(name = "reserves", uniqueConstraints={
#UniqueConstraint(columnNames = {"banque_id", "groupe_id"})
#Getter #Setter #NoArgsConstructor
public class Reserve {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "groupe_id")
private GroupeSanguin bloodGroup;
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "banque_id")
private Banque banque;
private int quantity;
}
i've found this solutions too.
#Entity
#Table(name = "reserves")
#Getter #Setter #NoArgsConstructor
#IdClass(ReserveId.class) //this annotation will tell that id that the
// the id will be represented by a class
public class Reserve {
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "groupe_id")
private GroupeSanguin groupeSanguin;
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "banque_id")
private Banque banque;
private int quantity;
}
and the id class should implements Serializable like this :
#Getter #Setter
public class ReserveId implements Serializable {
private Banque banque;
private GroupeSanguin groupeSanguin;
}
and finally the repository will be like that :
#Repository
public interface ReserveRepo extends JpaRepository<Reserve, ReserveId>{}
See your Reserve class has nowhere mentioned composite primary key. First you need to fix the model, You can refer to the solution here How to create and handle composite primary key in JPA

Infinite JSON in ManyToMany relationship mapped by Intermediary Table

I have 2 entities that relate to one another. These 2 entities should map to each other in a Many-To-Many relationship, however, I need to also have a timestamp of their respective relationship (when it happened), so I am trying to map them using an intermediary table.
Initially, the relationship was One-To-Many, but I realized that I actually need a Many-To-Many as the business logic requires this. The structure is still the same, as in there is a Parent-Child relationship, but this time, a child should have multiple parents as well.
My BaseEntity is an abstract class that contains the fields present in all the other entities:
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Id
#Min(100)
#Max(Integer.MAX_VALUE)
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#CreationTimestamp
#Column(name = "Created_At", updatable = false)
protected ZonedDateTime createdDate;
#UpdateTimestamp
#Column(name = "Updated_At")
protected ZonedDateTime updatedDate;
#NotNull
#Column(name = "Is_Active")
protected Boolean active = true;
}
Then I have my 2 entities that should relate in a Many-To-Many style. This is my first entity and should be the parent:
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "User")
#EqualsAndHashCode(callSuper = true)
#TypeDefs( {
#TypeDef(name = "json", typeClass = JsonStringType.class),
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class UserEntity extends BaseEntity {
#NotBlank
#Column(name = "User_Name", columnDefinition = "varchar(255) default 'N/A'")
private String userName;
#Nullable
#JoinColumn(name = "User_Id")
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<UserRole> roleList = new ArrayList<>();
}
My second entity is considered the child entity:
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "Role")
#Where(clause = "is_active = true")
#EqualsAndHashCode(callSuper = true)
public class RoleEntity extends BaseEntity {
#NotBlank
#Column(name = "Name")
private String name;
#JsonIgnore
#JoinColumn(name = "Role_Id")
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<UserRole> userList = new ArrayList<>();
}
I also have my intermediary entity:
#Data
#Entity
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Where(clause = "is_active = true")
#EqualsAndHashCode(callSuper = true)
#Table(name = "User_Role", uniqueConstraints= #UniqueConstraint(columnNames={"User_Id", "Role_Id"}))
public class UserRole extends BaseEntity {
// Adding #JsonIgnore here will only cause an error
#JoinColumn(name = "User_Id")
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, targetEntity = UserEntity.class)
private UserEntity user;
#JoinColumn(name = "Role_Id")
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, targetEntity = RoleEntity.class)
private RoleEntity role;
}
Problem now is that when I try to get my UserEntity, I get infinite recursion.
So far I've tried using #JsonIgnore, #JsonManagedReference, #JsonBackReference and it did not work or I simply don't know where or how to use them properly.
Recap:
2 entities mapped by Many-To-Many relationship;
Many-To-Many implemented using an intermediary entity and One-To-Many + Many-To-One associations;
Getting recursion when showing my UserEntity;
Update: I managed to get this fixed using a different approach described in my answer to this question.
I fixed this by implementing a Composite Key structure and just using the #JsonIgnore annotation:
#Getter
#Setter
#Embeddable
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor
public class UserRoleKey implements Serializable {
#Column(name = "User_Id")
Long userId;
#Column(name = "Role_Id")
Long roleId;
}
This gets to be used in the intermediary entity, which now doesn't use my BaseEntity anymore.
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "User_Role", uniqueConstraints= #UniqueConstraint(columnNames={"User_Id", "Role_Id"}))
public class UserRole {
#JsonIgnore
#EmbeddedId
private UserRoleKey id;
#JsonIgnore
#MapsId("userId")
#JoinColumn(name = "User_Id")
#ManyToOne(optional = false, targetEntity = UserEntity.class)
private UserEntity user;
#MapsId("roleId")
#JoinColumn(name = "Role_Id")
#ManyToOne(optional = false, targetEntity = RoleEntity.class)
private RoleEntity role;
#CreationTimestamp
#Column(name = "Created_At", updatable = false)
private ZonedDateTime createdDate;
}
Now, for my two entities, I have this definition:
UserEntity class (definition of the role):
#Nullable
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user", orphanRemoval = true)
private List<UserRole> roleList = new ArrayList<>();
RoleEntity class (definition of the user)
#Nullable
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "role", orphanRemoval = true)
private List<UserRole> userList = new ArrayList<>();
This seems to be working and no longer returns an infinite JSON recursion.

Repeated column in mapping for entity #OneToOne should be mapped with insert="false" update="false"

Hi I am trying below Entity classes for JPA Operations . I am getting an error Repeated column in mapping for entity #OneToOne should be mapped with insert="false" update="false" for column LOAN_ID . I tried some options and tried to follow some suggestions in other posts but nothing seems work , every try its giving some error . What is the mistake i am doing .
LOAN_UNDERWRITING - PK is LOAN_ID
LOAN_UNDERWRITING_STATUS - PK is LOAN_ID and UWS_ADD_DATE
Loans - PK is LOAN_ID
Root Entity Class
public class Loans {
#OneToOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
#JoinColumn(name = "LOAN_ID")
private LoanUnderWriting loanUnderWriting;
}
LOAN_UNDERWRITING - Entity Class
#DynamicUpdate
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Table(name = "LOAN_UNDERWRITING")
#Entity
public class LoanUnderWriting {
#Id
#Column(name = "LOAN_ID")
private Long loanId;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "UW_ADD_DATE"),
#JoinColumn(name = "LOAN_ID") })
private LoanUnderWritingStatus loanUnderWritingStatus;
}
LOAN_UNDERWRITING_STATUS-Entity Class
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Table(name = "LOAN_UNDERWRITING_STATUS")
#Entity
public class LoanUnderWritingStatus {
#EmbeddedId
private LoanUnderWritingStatusId loanUnderWritingStatusId;
}
LoanUnderWritingStatusId Class
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Embeddable
public class LoanUnderWritingStatusId implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name = "LOAN_ID")
private Long loanId;
#Column(name = "UWS_ADD_DATE")
private String uwsAddDate;
}
Your mapping should have insertable = false, updatable = false in LoanUnderWriting Entity for LoanUnderWritingStatus as showun below.
#DynamicUpdate
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Table(name = "LOAN_UNDERWRITING")
#Entity
public class LoanUnderWriting {
#Id
#Column(name = "LOAN_ID")
private Long loanId;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "UW_ADD_DATE", referencedColumnName = "UW_ADD_DATE", insertable = false, updatable = false),
#JoinColumn(name = "LOAN_ID", referencedColumnName = "LOAN_ID", insertable = false, updatable = false) })
private LoanUnderWritingStatus loanUnderWritingStatus;
}

Saving multiple child takes too much time (5 sec +)

saving table with multiple children takes too much time to execute (more than 5 sec)
tried this,
spring.jpa.properties.hibernate.jdbc.batch_size=30
spring.jpa.properties.hibernate.order_inserts=true
Timesheet Model
package com.Erp.Model.TimeSheetModel;
#Data
#Getter
#Setter
#Entity
#Table(name = "timesheet")
#JsonIdentityInfo(generator =
ObjectIdGenerators.PropertyGenerator.class,property="id", scope =
Timesheet.class)
public class Timesheet extends BaseEntity{
#ManyToOne
#JoinColumn(name = "employee_personal_information_id")
private EmployeePersonalInformation employeePersonalInformation;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "timesheet_id")
private Collection<TimesheetBudget> timesheetBudget;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "timesheet_id")
private Collection<TimesheetDateType> timesheetDateType;
}
TimesheetBudget Model
package com.Erp.Model.TimeSheetModel;
#Setter
#Getter
#Entity
#Table(name = "timesheet_budget")
#JsonIdentityInfo(generator =
ObjectIdGenerators.PropertyGenerator.class,property="id", scope =
TimesheetBudget.class)
public class TimesheetBudget extends BaseEntity {
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "timesheet_budget_id")
private Collection<TimesheetHours> timesheetHours;
#ManyToOne(fetch= FetchType.LAZY)
#JsonIgnore
private Timesheet timesheet;
}
TimesheetHours Model
package com.Erp.Model.TimeSheetModel;
#Entity
#Getter
#Setter
#Table(name = "timesheet_hours")
public class TimesheetHours extends BaseEntity {
#ManyToOne(fetch=FetchType.LAZY )
#JsonIgnore
private TimesheetBudget timesheetBudget;
}
TimesheetDateType Model
package com.Erp.Model.TimeSheetModel;
#Setter
#Getter
#Entity
#Table(name="timesheet_date_type")
#JsonIdentityInfo(generator =
ObjectIdGenerators.PropertyGenerator.class,property="id", scope =
TimesheetDateType.class)
public class TimesheetDateType extends BaseEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JsonIgnore
private Timesheet timesheet;
}
Timesheet Service
package com.Erp.Service.TimeSheetService;
#Service
public class TimesheetService {
#Autowired
TimesheetRepository timesheetRepository;
public ResponseEntity<String> saveTimesheet(Timesheet timesheet) {
timesheetRepository.save(timesheet);
return ResponseEntity.ok().body("Timesheet Saved Successfully.");
}
}
Timesheet Repository
package com.Erp.Repository.TimesheetRepository;
#Repository
public interface TimesheetRepository extends JpaRepository<Timesheet,
Integer>{
}

Issue with JPA. When fetchin eager parent all of its lazy children are also fetched [duplicate]

This question already has answers here:
How can I make a JPA OneToOne relation lazy
(12 answers)
Closed 4 years ago.
I am making a spring-boot project and currently I am facing a problem with lazy fetching. I have three classes one that is fetching its children with eager(Incident) and two that are with lazy(FileContent, FileStorage). The structure is:
Incident(1) -> (m)FileContent(1) -> (m)FileStorage.
Whenever I fetch from Incidet all of the fileContents and all of the fileStorages are also fetched. This should not be happening, fileStorages should not be fetched. It would be great if someone could tell me why the code behaves like this and help me fix It.
These are the classes:
#Getter
#Setter
#Entity
public class Incident extends BaseEntity {
#JsonIgnore
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "incident", orphanRemoval = true)
private List<FileContent> fileContent;
}
#Entity
#Getter
#Setter
public class FileContent extends BaseEntity {
#Column
private String fileName;
#OneToOne(mappedBy = "fileContent", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private FileStorage fileStorage;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "incident_id")
#LazyCollection(LazyCollectionOption.TRUE)
private Incident incident;
}
#Getter
#Setter
#Entity
public class FileStorage extends BaseEntity {
#Lob
#Column
private byte[] content;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_content_id")
private FileContent fileContent;
}
#Service(value = "ins")
public class IncidentService {
public Page<Incident> findAll(Pageable pageable) {
Page<Incident> incidents = incidentRepository.findAll(pageable);
if (CollectionUtils.isEmpty(incidents.getContent())) {
return null;
}
return incidents;
}
}
And this is the yml properties file
application.yml
- open-in-view: false
spring boot jpa java
Changed #OneToOne(fetch = FetchType.LAZY), to #OneToOne(optional = false, fetch = FetchType.LAZY) and it worked fine.

Resources