I'm building an application using AngularJs and Rest services (RestEasy) where I need to display a list of products. Once the list is loaded when the user clicks on one of the products, the details and images of this product are loaded.
I don't want to load the collections associated to the products (i.e Images) when I display the list of all products but only when I need the details of one of them, for performance reasons, so I'm using Lazy load.
Hibernate is doing fine and I can see that initially I only load some of the atributes but not the collections, however in the rest service, when Jackson tries to access the collection to serialize it, I'm getting this famous exception:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.domainmodel.Product.Images
Of course at that moment there is no longer Session opened and the database transaction has been commited. I don't want to keep the session opened. So searching on the net I saw that we can tell Jackson not to serialize a property using the annotation @JsonIgnore. This annotation has to be placed in the property or getter of the Entity (POJO), so basically, if I tell Jackson not to serialize this collection when serializing to JSON, it will solve the problem temporarily but once I need to load the product with the collection because the user has clicked on it, it won't serialize the collection so I will have this problem later. So I don't think this is a solution for me. Any ideas, advices on how to solve this situation?? I post the code of the entity and the rest service here. Thank you in advance!!
@Entity
@Table(name = "PRODUCTS")
public class Product implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@Column(name = "PATH_TO_IMAGE", nullable = false, insertable = true, updatable = true)
private String pathToImage;
@Column(name="DESCRIPTION",nullable=true, insertable = true, updatable = true)
private String description;
@ManyToOne(optional = false)
@JoinColumn(name = "XID_PRODUCT_TYPE", nullable = false, insertable = false, updatable = false)
private ProductType productType;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "PRODUCT_IMAGE",
joinColumns = {@JoinColumn(name = "XID_PRODUCT", referencedColumnName = "ID")},
inverseJoinColumns = {@JoinColumn(name = "XID_IMAGE", referencedColumnName = "ID")})
private List<Image> images;
... getters and setters
}
And then the code of the rest service:
@Path("/products")
public class ProductsService extends CommonService{
private static final Logger log = Logger.getLogger(ProductsService.class);
@EJB
private ProductsServiceHandler handler;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAllProducts(@Context Request request, @Context HttpHeaders httpHeaders)
{
try
{
List<Product> products=handler.findAllProducts();
return Response.ok(products).header(ALLOW_ORIGIN_HEADER, "*").build();
}
catch(Exception e){return Response.status(Status.INTERNAL_SERVER_ERROR).build();}
}
}
The complete stackstrace as requested:
2015-02-03 00:35:41,085 ERROR [io.undertow.request] (default task-9) UT005023: Exception handling request to /arenaclub/rest/products: org.jboss.resteasy.spi.UnhandledException: Response is committed, can't handle exception
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:148) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:432) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:376) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) [resteasy-jaxrs-3.0.8.Final.jar:]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:56) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:177) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:727) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_25]
at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_25]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.fgonzalez.domainmodel.Product.images, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.fgonzalez.domainmodel.Product["images"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:197) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:187) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:652) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:114) [jackson-databind-2.3.2.jar:2.3.2]
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:610) [jackson-databind-2.3.2.jar:2.3.2]
at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.writeTo(ResteasyJackson2Provider.java:186) [resteasy-jackson2-provider-3.0.8.Final.jar:]
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.writeTo(AbstractWriterInterceptorContext.java:129) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.interception.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:62) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:118) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.security.doseta.DigitalSigningInterceptor.aroundWriteTo(DigitalSigningInterceptor.java:143) [resteasy-crypto-3.0.8.Final.jar:]
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:122) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPEncodingInterceptor.aroundWriteTo(GZIPEncodingInterceptor.java:100) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:122) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:99) [resteasy-jaxrs-3.0.8.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:427) [resteasy-jaxrs-3.0.8.Final.jar:]
... 32 more