2

I'm having an issue with converting an application to separate REST Server + Web Application rather than having a single application that handles pages + business logic.

I'm having a problem with an org.hibernate.LazyInitializationException being thrown when Jackson is serialising the output.

Below is my JPA configuration and the class in question. I'm aware the lazy initialisation is being caused by the List member, but I don't want this to be populated in the JSON returned. Hence the @JsonIgnore annotation.

PersistenceConfiguration.java

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackageClasses = {ForumRepository.class})
public class PersistenceConfiguration {

@Bean
public EntityManagerFactory entityManagerFactory() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();

    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.mypackage.forum.api.models");
    factory.setDataSource(secureDataSource());
    factory.afterPropertiesSet();

    return factory.getObject();
}

@Bean
public JpaTransactionManager transactionManager() {
    EntityManagerFactory factory = entityManagerFactory();
    return new JpaTransactionManager(factory);
}

@Bean
public HibernateExceptionTranslator exceptionTranslator() {
    return new HibernateExceptionTranslator();
}

@Bean
public DataSource secureDataSource() {
    try {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:jboss/datasources/ForumDS");
    } catch (Exception e) {
        return null;
    }
}
}

ForumGroup.java

@Entity
public class ForumGroup {

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

@JsonIgnore
@OneToMany(mappedBy = "group")
private List<Forum> forums;

private String name;
private String description;

public Integer getId() {
    return id;
}

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

public List<Forum> getForums() {
    return forums;
}

public void setForums(List<Forum> forums) {
    this.forums = forums;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    ForumGroup that = (ForumGroup) o;

    if (id != null ? !id.equals(that.id) : that.id != null) return false;
    if (name != null ? !name.equals(that.name) : that.name != null) return false;

    return true;
}

@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
}

@Override
public String toString() {
    return "ForumGroup{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", description='" + description + '\'' +
            '}';
}
}

I presume that I need to configure some sort of Session Manager but not sure the best way to go about doing it in JavaConfig, I've tried various methods via Google with no joy.

Any help would be much appreciated.

Update

I've now managed to resolve this by 1) Adding the @Fetch() annotation to the relevant collections, which means that the collections get populated 2) I have stopped Entities/Models being returned as JSON objects and instead use separate DTOs

3
  • 1
    I (and I think the people who already answered have the same problem) am having a bit of trouble understanding what your real question is. I -think- it is that you do not want to emit the forums in the JSON data, thus you slap the JsonIgnore annotation on it. Yet you -still- get the lazy init error because the forum collection is being touched for some as yet mysterious reason. Am I correct?
    – Gimby
    Commented May 22, 2014 at 11:49
  • 1
    As Gimby said if you don't want to populated the JSON with the forums list, fix this LazyInitializationException by populate the List while the session is still open is not the better trick. Your service layer (and your REST controller layer) must expose DTOs (Data transfer objects) instead of @Entity objects. In that way it will be easier to deal with Lazy while mapping entity with a DTO in your Service layer.
    – Basemasta
    Commented May 22, 2014 at 14:39
  • You're correct, I don't want the contents of the collection returned in the JSON. So in theory the Lazy Init exception shouldn't be getting thrown because it should just ignore that. Using a combination of Vlads answer, and separating the concept Models/Entities and DTOs I've solved this issue. Thank you all for your help
    – Andy Esser
    Commented May 22, 2014 at 15:18

2 Answers 2

3

org.hibernate.LazyInitializationException happens when call lazy fields outside from session.
In your situation , it's seams you select ForumGroup entities and then, outside from session you trying call entity.getForums(). That's why happening LazyInitializationException.

If you need that collection, then load them eagerly. You can do that by calling:
entity.getForums().size();.Remember, call this inside the session

You can use anotation, to to load collection EAGERLY by default : @ManyToOne(fetch = FetchType.EAGER)

2

You just need to fetch the ForumGroup along with its forums list.

This can be achieved with a LEFT JOIN FETCH whenever you retrieve the ForumGroup you are interested in:

"from ForumGroup as fg " +
"left join fetch fg.forums "

You can assign a default fetching strategy, but this is a decision that will affect subsequent queries, so make sure you know the trade-offs:

Use a join fetch mode:

@JsonIgnore
@OneToMany(mappedBy = "group")
@Fetch(FetchMode.JOIN)    
private List<Forum> forums = new ArrayList<Forum>();

Or a sub-select fetch mode:

@JsonIgnore
@OneToMany(mappedBy = "group")
@Fetch(FetchMode.SUBSELECT)
private List<Forum> forums = new ArrayList<Forum>();

And always initialize your collections, never let them assigned to null.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.