0

I'm fetching Company along with productSLA using join fetch query, since the Company has userlist and it doesn't get initialized. Therefore at the time when i send response using responseentity.ok it throws lazy init exception. I don't want user list for that purpose is there any way i can send it to front end without getting lazy init exception some one suggested me to do this using dto.

I am using angular on front end. When i was using jsp i never faced this kind of problem.

@Entity
@Table(name = "USER_TABLE")
public class User {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Integer userId;

 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL,fetch=FetchType.EAGER)
 private List<Ticket> raisedTickets;

 @NotNull
 @Column(unique = true)
 @Email(message = "Invalid Email")
 private String email;

 @NotNull
 @Column
 @Length(min = 4, max = 12, message = "First name must be between 4 to 12 character long")
 private String firstName;

 @NotNull
 @Column
 @Length(min = 4, max = 12, message = "Last name must be between 4 to 12 character long")
 private String lastName;

 @NotNull
 @Column
 @Length(min = 8, max = 100, message = "Password must be 4 to 12 character long")
 private String password;

 @NotNull
 @Column
 @Length(min = 3, max = 30, message = "Company Name must be between 3 to 12 character long")
 private String companyName;

 @Column(name = "USER_ROLE")
 @Enumerated(EnumType.STRING)
 private UserRolesEnum userRole;

 @ManyToOne
 @JoinColumn(name = "COMPANY_ID", nullable = false)
 @NotNull
 private Company company;

 @OneToMany(mappedBy="user", cascade=CascadeType.ALL)
 private List<ProductAssociated> productAssociatedList=new ArrayList<ProductAssociated>();

 public User() {
 }

 public User(String firstName, String lastName, String email, String password, String companyName,
   UserRolesEnum role) {
  super();
  this.firstName = firstName;
  this.lastName = lastName;
  this.email = email;
  this.password = password;
  this.companyName = companyName;
  this.userRole = role;
 }

 public Integer getUserId() {
  return userId;
 }

 public void setUserId(Integer id) {
  this.userId = id;
 }

 public List<Ticket> getRaisedTickets() {
  return raisedTickets;
 }
 public void setRaisedTickets(List<Ticket> raisedTickets) {
  this.raisedTickets = raisedTickets;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }

 public String getCompanyName() {
  return companyName;
 }

 public void setCompanyName(String companyName) {
  this.companyName = companyName;
 }

 public UserRolesEnum getUserRole() {
  return userRole;
 }

 public void setUserRole(UserRolesEnum userRole) {
  this.userRole = userRole;
 }

 public Company getCompany() {
  return company;
 }

 public void setCompany(Company company) {
  this.company = company;
 }

 public List<ProductAssociated> getProductAssociatedList() {
  return productAssociatedList;
 }

 public void setProductAssociatedList(List<ProductAssociated> productAssociatedList) {
  this.productAssociatedList = productAssociatedList;
 }

 public void addProductAssociated(ProductAssociated productAssociated) {
  productAssociatedList.add(productAssociated);
  productAssociated.setUser(this);
}  





    @Entity
@Table(name="PRODUCT_SLA")
public class ProductSLA {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="SLA_ID")
 private Integer slaId;

 @NotNull
 @Column(name="RESPONSE_TIME")
 private int responseTime;

 @Column(name="RESOLVE_TIME")
 private int resolveTime;

 @NotNull
 @Column(name="PRIORITY")
 @Enumerated(EnumType.STRING)
 private PriorityEnum priority;

 @ManyToOne
 @JoinColumn(name="COMPANY_ID", nullable = false)
 private Company company;

 @ManyToOne
 @JoinColumn(name="PRODUCT_ID", nullable = false)
 private Product product;

 public ProductSLA() {
  super();
 }

 public ProductSLA(Integer slaId, int responseTime, int resolveTime, PriorityEnum priority) {
  super();
  this.slaId = slaId;
  this.responseTime = responseTime;
  this.resolveTime = resolveTime;
  this.priority = priority;
 }

 public Integer getSlaId() {
  return slaId;
 }

 public void setSlaId(Integer slaId) {
  this.slaId = slaId;
 }

 public int getResponseTime() {
  return responseTime;
 }

 public void setResponseTime(int responseTime) {
  this.responseTime = responseTime;
 }

 public int getResolveTime() {
  return resolveTime;
 }

 public void setResolveTime(int resolveTime) {
  this.resolveTime = resolveTime;
 }

 public PriorityEnum getPriority() {
  return priority;
 }

 public void setPriority(PriorityEnum priority) {
  this.priority = priority;
 }

 public Company getCompany() {
  return company;
 }

 public void setCompany(Company company) {
  this.company = company;
 }

 public Product getProduct() {
  return product;
 }

 public void setProduct(Product product) {
  this.product = product;
 }

}



    @Entity
@Table(name = "COMPANY_TABLE")
public class Company {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "COMPANY_ID")
 private Integer companyId;

 @NotNull
 @Column(name = "COMPANY_NAME", unique = true)
 private String companyName;

 @NotNull
 @Column(name = "ADDRESS_LINE1")
 private String addressLine1;

 @Column(name = "ADDRESS_LINE2")
 private String addressLine2;

 @NotNull
 @Column(name = "CITY")
 private String city;

 @NotNull

 @Column(name="STATE_NAME")

 private String state;

 @NotNull
 @Column(name = "COUNTRY")
 private String country;

 @NotNull
 @Column(name = "PHONE")
 private String phone;

 @NotNull
 @Column(name = "POSTAL_CODE")
 private String postalCode;

 @NotNull
 @Column(name = "COMPANY_WEBSITE")
 private String companyWebsite;

 @OneToMany( mappedBy = "company", cascade = CascadeType.ALL)
 private List<User> userList = new ArrayList<User>();

 @OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
 private List<ProductSLA> productSLAList = new ArrayList<ProductSLA>();

 @OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval=true)
 private List<AccessLevel> accessLevelList=new ArrayList<AccessLevel>();

 public Company() {
  super();
 }

 public Company(Integer companyId, String companyName, String addressLine1, String addressLine2, String city,
   String state, String country, String phone, String postalCode, String companyWebsite) {
  super();
  this.companyId = companyId;
  this.companyName = companyName;
  this.addressLine1 = addressLine1;
  this.addressLine2 = addressLine2;
  this.city = city;
  this.state = state;
  this.country = country;
  this.phone = phone;
  this.postalCode = postalCode;
  this.companyWebsite = companyWebsite;
 }

 public Integer getCompanyId() {
  return companyId;
 }

 public void setCompanyId(Integer companyId) {
  this.companyId = companyId;
 }

 public String getCompanyName() {
  return companyName;
 }

 public void setCompanyName(String companyName) {
  this.companyName = companyName;
 }

 public String getAddressLine1() {
  return addressLine1;
 }

 public void setAddressLine1(String addressLine1) {
  this.addressLine1 = addressLine1;
 }

 public String getAddressLine2() {
  return addressLine2;
 }

 public void setAddressLine2(String addressLine2) {
  this.addressLine2 = addressLine2;
 }

 public String getCity() {
  return city;
 }

 public void setCity(String city) {
  this.city = city;
 }

 public String getState() {
  return state;
 }

 public void setState(String state) {
  this.state = state;
 }

 public String getCountry() {
  return country;
 }

 public void setCountry(String country) {
  this.country = country;
 }

 public String getPhone() {
  return phone;
 }

 public void setPhone(String phone) {
  this.phone = phone;
 }

 public String getPostalCode() {
  return postalCode;
 }

 public void setPostalCode(String postalCode) {
  this.postalCode = postalCode;
 }

 public String getCompanyWebsite() {
  return companyWebsite;
 }

 public void setCompanyWebsite(String companyWebsite) {
  this.companyWebsite = companyWebsite;
 }

 public List<User> getUserList() {
  return userList;
 }

 public void setUserList(List<User> userList) {
  this.userList = userList;
 }

 public void addUser(User user) {
  userList.add(user);
  user.setCompany(this);
 }

 public List<ProductSLA> getProductSLAList() {
  return productSLAList;
 }

 public void setProductSLAList(List<ProductSLA> productSLAList) {
  this.productSLAList = productSLAList;
 }

 public void addProductSLA(ProductSLA productSLA) {
  productSLAList.add(productSLA);
  productSLA.setCompany(this);
 }


 public List<AccessLevel> getAccessLevelList() {
  return accessLevelList;
 }

 public void setAccessLevelList(List<AccessLevel> accessLevelList) {
  this.accessLevelList = accessLevelList;
 }

 public void addAccessLevel(AccessLevel accessLevel) {
  accessLevelList.add(accessLevel);
  accessLevel.setCompany(this);
 }
}

edit i found solutions but i am confused which one to use and how to use, because there are many solutions there. Avoid Jackson serialization on non fetched lazy objects

2 Answers2

0

Assuming your hibernate session is closed already in the controller (which is a fair assumption to make since we don't want to expose our hibernate sessions outside spring/hibernate layer) you will run into this type of problem if you try to access a collection which was not loaded when it was inside the session.

Alright!

I'm also assuming that you are returning a one or collection of "hibernate managed entities" as opposed to DTOs. What I'm sensing is that when that entity is converted into JSON all the getters are called by underlying framework unless they are marked 'ignore' (or something like that). OR may be your UI is calling userList at which point it's throwing exception since a proxy was returned by hibernate.

Regardless, it's better to return a DTO and populate it however way you like. There are various reasons why returning a DTO (or a collection of DTOs) is preferred over returning an entity.

Sanjeev Dhiman
  • 1,169
  • 1
  • 11
  • 20
  • 1
    To avoid the effort of creating a DTO and the associated mapping code al alternative is to use return a JsonView which would exclude the lazy field. https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring – Alan Hay Oct 06 '17 at 19:43
  • I would not follow the accepted solution; it may work easily for simple cases but it may be tricky to provide custom support for complex cases. I would suggest you to use either ModelMapper or JsonView (as @Alan suggested) or some other DTO handling framework. – Sanjeev Dhiman Oct 06 '17 at 20:02
0

To resolve this problem, i've used http message converter,

Application Configuration looks like this:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(jacksonMessageConverter());
    super.configureMessageConverters(converters);
}

and

public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
    MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new Hibernate5Module());
    messageConverter.setObjectMapper(mapper);
    return messageConverter;

}

Dependency Required

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate5</artifactId>
        <version>2.8.7</version>
    </dependency>

There is a dirty solution also for this,if you are willing to modify every getters: jackson 2 object to json ignore lazy loading