1 Reply Latest reply on Jan 16, 2014 8:50 AM by smarlow

    Problem with JSON-P and JPA lazy fetch

    dbschofield

      I have a simple jax-rs service which returns JSON.

       

      @TransactionAttribute(TransactionAttributeType.REQUIRED)

      @Stateless

      @Path("roles")

      public class RoleResource {

        

          @EJB private ENC enc;

        

          @GET

          @Produces("text/json")

          public List<Role> roles(){

              return enc.getRoles();

          }

      }

       

      The JSON data to return is a JPA entity.

       

      @Entity

      public class Role implements Serializable {

       

          @Id

          private String name;

        

          @ManyToMany(fetch=FetchType.EAGER)

          @JoinTable(

              name="role_profile_map",

              joinColumns={@JoinColumn(name="role", referencedColumnName="name")},

              inverseJoinColumns={@JoinColumn(name="profile", referencedColumnName="name")})

          private Set<Profile> profiles;

        

          @ManyToMany

          @JoinTable(

              name="role_environment_map",

              joinColumns={@JoinColumn(name="role", referencedColumnName="name")},

              inverseJoinColumns={@JoinColumn(name="environment", referencedColumnName="name")})

          private Set<Environment> environments;

          ...

      }

       

      If I want the ManyToMany relationships to be lazily fetched I get the following exception.

       

      17:45:11,007 ERROR [io.undertow.request] (default task-11) UT005023: Exception handling request to /paas/rest/roles: org.jboss.resteasy.spi.UnhandledException: org.codehaus.jackson.map.JsonMappingException: failed to lazily initialize a collection of role: com.xyz.paas.entity.Role.environments, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.xyz.paas.entity.Role["environments"])

          at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:247) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:149) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:432) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:376) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) [resteasy-jaxrs-3.0.6.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:87) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:70)

          at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:67) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:70) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          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.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.server.Connectors.executeRootHandler(Connectors.java:164) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:654) [undertow-core-1.0.0.Beta30.jar:1.0.0.Beta30]

          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_40]

          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_40]

          at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_40]

      Caused by: org.codehaus.jackson.map.JsonMappingException: failed to lazily initialize a collection of role: com.xyz.paas.entity.Role.environments, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.xyz.paas.entity.Role["environments"])

          at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:72) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:86) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:659) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:271) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ObjectWriter.writeValue(ObjectWriter.java:325) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.jaxrs.JacksonJsonProvider.writeTo(JacksonJsonProvider.java:557)

          at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.writeTo(AbstractWriterInterceptorContext.java:129) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.interception.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:62) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:118) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.security.doseta.DigitalSigningInterceptor.aroundWriteTo(DigitalSigningInterceptor.java:143) [resteasy-crypto-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:122) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.plugins.interceptors.encoding.GZIPEncodingInterceptor.aroundWriteTo(GZIPEncodingInterceptor.java:100) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:122) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:99) [resteasy-jaxrs-3.0.6.Final.jar:]

          at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:427) [resteasy-jaxrs-3.0.6.Final.jar:]

          ... 33 more

      Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.xyz.paas.entity.Role.environments, could not initialize proxy - no Session

          at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:572) [hibernate-core-4.3.0.Final.jar:4.3.0.Final]

          at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:212) [hibernate-core-4.3.0.Final.jar:4.3.0.Final]

          at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:551) [hibernate-core-4.3.0.Final.jar:4.3.0.Final]

          at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:140) [hibernate-core-4.3.0.Final.jar:4.3.0.Final]

          at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180) [hibernate-core-4.3.0.Final.jar:4.3.0.Final]

          at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:45) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:86) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150) [jackson-mapper-asl-1.9.12.jar:1.9.12]

          ... 50 more

       

      My understanding is this exception is thrown because the container managed transaction for the hibernate session has already ended by the time hibernate attempts to lazily fetch the environments set needed for the JSON conversion.  I'm wondering if WildFly should (or some way can) make the conversion of the JPA entity to JSON part of the container managed transaction.  Or is their a compelling reason not to do this?

        • 1. Re: Problem with JSON-P and JPA lazy fetch
          smarlow

          My understanding is this exception is thrown because the container managed transaction for the hibernate session has already ended by the time hibernate attempts to lazily fetch the environments set needed for the JSON conversion.  I'm wondering if WildFly should (or some way can) make the conversion of the JPA entity to JSON part of the container managed transaction.  Or is their a compelling reason not to do this?

          There are a few ways that you could avoid the exception.

          1. Change the ManyToMany FetchType from the default of LAZY to EAGER (fetch = FetchType.EAGER).  This only works if you want to change all uses of the entity, to eagerly fetch all elements of the collection.  This avoids the lazy initialization error by disabling lazy fetching for the ManyToMany collection. 
          2. For a more limited switch to eagerly fetch the collection, try referencing the collection within the container managed transaction (before returning).
          3. The other typical way to avoid the org.hibernate.LazyInitializationException, is to reference the collection within a container managed transaction (e.g. on a subsequent invocation), use EntityManager.merge(entity) to reattach the detached entity back into a managed persistence context (you should then be able to access the lazily fetched data).

           

          I'm not in love with any of these solutions (would be nicer to have a auto-magic way to do one of them) but perhaps one will work for you.

           

          Scott