I'm getting crazy with an error that I'm having using Spring MVC 3.1.2 and Jackson 2.
I have the following model Class:
@Entity
@Table(name = "USER")
@JsonIgnoreProperties(ignoreUnknown=true)
public class User implements Serializable
{
@Id
@SequenceGenerator(name = "USER_ID", sequenceName = "USER_ID_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_ID")
private Long id;
@Column(length = 50, nullable = false)
private String firstName;
@Column(length = 50, nullable = false)
private String lastName;
@ManyToMany
@JoinTable(name = "FRIENDS",
joinColumns = @JoinColumn(name = "personId"),
inverseJoinColumns = @JoinColumn(name = "friendId")
)
@JsonManagedReference
private List<User> friends;
@ManyToMany
@JoinTable(name="FRIENDS",
joinColumns=@JoinColumn(name="friendId"),
inverseJoinColumns=@JoinColumn(name="personId")
)
@JsonIgnore
private List<User> friendOf;
// Other attributes and methods...
}
When I get an single instance of User it is correctly serialized by Jackson. But when I try to get an instance of User that contains friends, the following exception is thrown:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.frooid.model.User.friends, no session or session was closed
I'm getting this instance using a single HQL:
select u from User u left join fetch u.friends f where u.id = :id
Thanks to everybody!
ToMany associations are lazy-loaded by default. This means the the friens of your users will only be loaded from the database when invoking a method of the
friends
list.This lazy-loading can only occur while the session used to load the user is open. So if you return the user from your transactional method without the friends list loaded, the session will be closed, and trying to load the freinds list will lead to the exception you're getting.
So, if the client needs the freinds list to be loaded, ither fetch the friends using HQL, or force the initialization of the list, inside the service method, by calling a method on the list or by calling
Hibernate.initialize(user.getFriends())
.EDIT: since you have a fetch in your HQL, it should work. Another problem is that the bidirectional association is mapped twice: once on the
friends
field, and once on thefriendOf
field. One of those association must be marked as the inverse of the other using themappedBy
attribute:I had Similar issue. The approach was to create a new class(view) and adding this class in
@JsonView({NewClass1.class,NewClass2.class})
on each property, in the Entity where your properties are defined. You can choose the variables which you want to be loaded as part of your response and include the class in@JsonView
. Just as simple as that!Try using the
OpenSessionInViewFilter
while this is meant for accessing lazy initialized fields in your view it may keep the session open for Jackson to be able to access the collection.The
OpenSessionInViewFilter
binds a Hibernate Session to the thread for the entire processing of the request. Intended for the "Open Session in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.In Web.xml
API Documentation