There should be an easy way to handle returning the JPA entity with lazy loading from REST end-point.
See following example:
@Entity public class User { @OneToMany(mappedBy = "owner", fetch = FetchType.LAZY) List<Task> tasks; ... } @GET @Path("get/{id}") @Produces(MediaType.APPLICATION_JSON) public User getById(@PathParam("id") Long id) throws Exception { return userDao.getUser(id); }
This example returns code 500 and LazyInitializationException.
I am aware of several ways how to deal with this and return the collection:
1. Call a method on given collection (e.g. .size()) or iterate through it before returning an entity.
This is simple but it performs an additional query for each collection in given entity so it's bad for performance.
2. JPQL query with a fetch join in userDao:
Query q = this.em.createQuery("SELECT u FROM User u JOIN FETCH u.tasks t WHERE u.id = :id"); q.setParameter("id", id); User user = (User) q.getSingleResult(); return user;
This performs only one query but we need to write specific query for each combination of associations we need so this is not ideal if an entity contains lot of collections.
3. Named Entity Graph or Dynamic Entity Graph
EntityGraph graph = this.em.createEntityGraph(User.class); Subgraph tasksGraph = graph.addSubgraph("tasks"); Map hints = new HashMap(); hints.put("javax.persistence.loadgraph", graph); User user = this.em.find(User.class, id, hints);
This doesn't work when entity contains multiple Lists. It works only with Sets.
We should either clarify which approach is recommended (maybe none of the above?) or I propose to create new functionality - an annotation that would guarantee that all needed collections will be loaded (maybe by keeping the transaction open also in RESTEasy MessageBodyWriter classes).