Eric Huang
Eric Huang

Reputation: 1264

Spring Hibernate FetchType LazyInitializationException even when not calling association

I am just starting to learn about FetchType Lazy and Eager. I understand the difference but even if I set to Lazy its somehow still trying to get the associated data.

Relationship: 1 Person : Many Phones

Research attempts and tutorials viewed:

https://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/ http://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/ https://howtoprogramwithjava.com/hibernate-eager-vs-lazy-fetch-type/

I understand to get the associated data I will need to do it while still in session() So for my particular example In my Dao I will need something like this

  List<Person> persons = criteria.list();

    for(Person person : persons){

        Set sets = person.getPhones();

    }
    return persons;

So far correct?

But the problem is I am not calling person.getPhones() anywhere not in Dao, controller..etc but I am getting LazyInitializationEception. For the life of me can't seem to catch what is wrong.

Stack trace

Jun 19, 2017 2:24:01 PM org.apache.catalina.core.StandardWrapperValve invoke
 SEVERE: Servlet.service() for servlet [app-dispatcher] in context with path 
 [/uni-starter-onetomany] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session

Person.class

@Entity
@Table(name="person")
@Component
public class Person {

@Id
@GeneratedValue
private int person_id;

private String name;

private String age;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
private Set<Phone> phones;

//  Getter and setters

// ToString method by field name not by method

Phone.class

@Entity
@Table(name="phone")
@Component
public class Phone {

@Id
@GeneratedValue
private int phone_id;

private String type;

private String phone;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="person_person_id")
private Person person;

//  Getter and setters

PersonDao

    @Repository
 @Transactional
 @Component("personDao")
 public class PersonDao {

@Autowired
private SessionFactory sessionFactory;

public Session session(){
    return sessionFactory.getCurrentSession();
}

public List<Person> getPersonList(){
    Criteria criteria = session().createCriteria(Person.class);

    List<Person> persons = criteria.list();

    //  for(Person person : persons){
    //
    //    Set sets = person.getPhones();
    //
    //  }

    return persons;
}


public void saveOrUpdate(Person person){
    session().saveOrUpdate(person);
}

}

Controller

    // Get list
@RequestMapping(path="/list", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Map<String, Object> getListPerson(){

    Map<String, Object> data = new HashMap<String, Object>();

    List<Person> persons = personDao.getPersonList();       

    data.put("results", persons);

    System.out.println(persons);

    return data;
}

Question

  1. As long as I don't call person.getPhones() within the session it should only return person? if so what might be the problem here that I am getting LazyInitializationException?

  2. I also seen people setFetchMode() FetchMode.JOIN in the Dao class for example Hibernate Criteria Join with 3 Tables perhaps this could be subjective but what would be a better practice? any performance issues?

Any idea, links or articles are much appreciated...

UPDATE Thanks to Abassa removing Phone in from toString in Person.class fixes the problem. But I just realize that due to Jackson, during serialization it tries to fetch Phone ojbect.... is there a work around?

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session

Upvotes: 0

Views: 804

Answers (1)

Abass A
Abass A

Reputation: 743

Remove phones field from toString method in Person class.

When you call:

System.out.println(persons);

you try to access phones fields because println calls toString method for every person in the list so you get the LazyInitializationException.

Upvotes: 2

Related Questions