bielas
bielas

Reputation: 712

JPA generate fails with JSON

I cound't find any solution to manage that fail, so I decided to create a new question. I have a simple class

@Entity
public class Reservation {

// private Integer RESERVATION_ID;
// private Integer id;
private long code;
private Date date;
private Client reservationClient;
private WashType reservationWashType;
private Vehicle reservationVehicle;
private Wash reservationWash;
private Worker reservationWorkerPesel;
private Review reservationReview;
private ReservationReminder reservationReminder;
 }

Where I run a query like that:

  @Query("SELECT r FROM Reservation r JOIN FETCH r.reservationReminder where r.reservationWorkerPesel = :worker")
List<Reservation> findByReservationWorkerPesel(@Param("worker") Worker worker);

And at first I everything looks nice, but then I do some operations like that:

    public List<ReservationReminder> findByReservationWorkerPesel(Worker worker) {
    List<ReservationReminder> reservationReminderList = new ArrayList<>();
    List<Reservation> byReservationWorkerPesel = reservationDao.findByReservationWorkerPesel(worker);
    for (Reservation r : byReservationWorkerPesel) {
        if (r.getReservationReminder() != null && r.getReservationReminder().getChecked() == false)
            reservationReminderList.add(r.getReservationReminder());
    }
    return reservationReminderList;
}

And after that when I see how JSON looks like - it's strange, because:

[{"reservationReminderId":2,"reservation":{"code":263022,"date":1487851200000,"reservationClient":{"clientPesel":"91122619197","name":"Client 1","surname":"Client 1","email":"[email protected]","phone":"234567890","accountNumber":"34567897654345678987654356","clientUser":{"userId":3,"login":"client","passwordHash":"$2a$10$0jJMMzeh2CTRagk3hwRSlurx.mxLgR1aAUQOYBD9QFqbISeoTSVN.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":

....

[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":"$2a$10$6WrmwpwOdhv6UXBo2mYq8ucKiQTwvIwTHw23myo6.oujflh8pqKR.","userRole":{"roleId":3,"name":"CLIENT","users":[{"userId":8,"login":"clien5","passwordHash":{"timestamp":1489015140465,"status":200,"error":"OK","exception":"org.springframework.http.converter.HttpMessageNotWritableException","message":"Could not write content: Infinite recursion (StackOverflowError) (through reference chain: com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]-

...

\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"]->com.carwash.domains.Role[\"users\"]->org.hibernate.collection.internal.PersistentBag[0]->com.carwash.domains.User[\"userRole\"])","path":"/api/reservationreminder"}

What am I doing wrong?

Perhaps it can say you something - I don't why after making a GET method (only get) I got some those bugs?

enter image description here

Upvotes: 0

Views: 152

Answers (2)

bielas
bielas

Reputation: 712

@KLHauser

So how to manage the case if I have a class

@Entity
public class ReservationReminder {
private int reservationReminderId;
private Reservation reservation;
private boolean isChecked;
private Date checkedDate;

and Reservation class

@Entity
public class Reservation {

// private Integer RESERVATION_ID;
// private Integer id;
private long code;
private Date date;
private Client reservationClient;
private WashType reservationWashType;
private Vehicle reservationVehicle;
private Wash reservationWash;
private Worker reservationWorkerPesel;
private Review reservationReview;
private ReservationReminder reservationReminder;

@Entity
public class Worker {

private String workerPesel;
private String name;
private String surname;
private Date startDateWorking;
private String accountNumber;
private List<Review> workerReview;
private Adress workerAdress;
private List<LaborHistory> workerLaborHistory;
private Wash workerWash;
//private List<WorkerWorkerTime> workerWorkTime;
// private Role WORKER_ROLE;
private User workerUser;
private List<Reservation> workerReservation;

And I'd like to load ReservationReminder class with Worker from Reservation class? If I use @JsonIgonre like that

@OneToOne(mappedBy = "reservationReminder", fetch = FetchType.LAZY)
@JsonIgnore
public Reservation getReservation() {
    return reservation;
}

I only got a Json with checkedDate, isChecked and reservationReminderId from ReservationReminder

Upvotes: 0

KLHauser
KLHauser

Reputation: 876

You have a Infinite recursion between your User and UserRole object. Whenever a user is serialized his related user roles are also serialized. Since user roles does also have a relation back to the user you have the recursion.

Solution to this could be to use @JsonManagedReference (added to the relation in User) and @JsonBackReference (realtion at UserRoles). See also here: Infinite Recursion with Jackson JSON and Hibernate JPA issue

@Entity
public class User
   ...
   @JsonManagedReference
   private Set<UserRole> userRoles;


@Entity
public class UserRole
   ...
   @JsonBackReference
   private User user;

@JsonManagedReference would mean that during serialization the relation part is taken into account. So the related user roles would be also serialized. Since there the related connection is marked with @JsonBackReference serialization stops to go further.

Upvotes: 1

Related Questions