Home > Software design >  Could not write JSON: failed to lazily initialize a collection of role:
Could not write JSON: failed to lazily initialize a collection of role:

Time:11-28

i am having an error with the fetch type and i dont know how to fix it! Please help me if u can. :D. Using java 8

THE COMMAND LINE RUNNER:

    @Autowired CustomTableRepository tr;
    @Autowired UserRepository ur;
    @Autowired RoleRepository rr;
    @Bean
    CommandLineRunner commandLineRunner() {
        return args -> {
            tr.save(new CustomTable(null, true, null));
            tr.save(new CustomTable(null, true, null));
            tr.save(new CustomTable(null, true, null));
            tr.save(new CustomTable(null, true, null));
            tr.save(new CustomTable(null, true, null));

            ur.save(new User(null, "cpthermes", "thanatos", 123987456l, 3123231l, null,null));
            ur.save(new User(null, "moni1008", "milky", 123987456l, 31232131l, null, null));
            ur.save(new User(null, "mario", "zoro123", 1231231l, 32123l, null, null));

            
        };
    }

THE MODEL CLASSES:

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Reservation {
    
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private Boolean accepted;
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
    @OneToOne
    @JoinColumn(name = "table_id")
    private CustomTable table;
    private LocalTime time;
}



@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String username;
    private String password;
    private Long number;
    private Long balance;
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Reservation> reservations;
    @ManyToMany
    private Collection<Role> roles;
}

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
    @Id
    @GeneratedValue
    private Long id;
    private String type;
}

THE ERROR:

Could not write JSON: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.mile.pc.mile.restoraunt.app.model.User["reservations"])
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.mile.pc.mile.restoraunt.app.model.User["reservations"])

.................... .................... .................... .................... .................... .................... Ty for reading.

CodePudding user response:

The issue is that at the time Spring tries to convert your entities to JSON, Hibernate has no way of retrieving the lazy-loaded reservations from the database. You have a couple of possibilities to fix this:

  • Using FetchType.EAGER strategy
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String username;
    private String password;
    private Long number;
    private Long balance;
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Reservation> reservations;
    @ManyToMany
    private Collection<Role> roles;
}
  • Using Join fetching in your custom Repository method:
@Query(value = "SELECT u FROM User u JOIN FETCH u.reservations")
List<User> findAllUsers();

You can read more about this issue at the following online resource: https://www.baeldung.com/hibernate-initialize-proxy-exception

CodePudding user response:

For @OneToMany and @ManyToMany hibernate by default uses lazy fetch approach. i.e. It simply does not load your child entities when you ask it get the parent entity. So you can have two simpler ways to overcome this problem.

  1. Use fetch=FetchType.EAGER on Reservations.

Simply update below in Role class.

@OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Reservation> reservations;

But be aware about the performance issue. Hibernate is going to load the Reservation entities all the time when you ask for a Role entity. If that is not a concern for your application, you can easily go for this.

  1. Use JOIN FETCH approach

Define a @Query method using join fetch and use that instead of predefined find() method. In that way you can ask hibernate what other tables to load whenever you are asking to load the parent entity.

@Query(value = "SELECT u FROM User u JOIN FETCH u.reservations")
List<User> findUsersWithReservations();

Below article has further details around it along with some other approaches.

https://thorben-janssen.com/lazyinitializationexception/

  • Related