smallrye-graphql: Problem with PersistentSet and Hibernate

I’m running into an issue with GraphQL not playing nice with Hibernate and JPA.

I’ve got an AppUser class with a @ManyToMany join to a set of AppRole. I’m using the SmallRye GraphQL client v1.3.3 as the UI, and smallrye graphql v1.1.0 on the back end. If I request basic fields from the AppUser without accessing the set of roles, it works fine. But if I try to access the roles then I get the following exception:

15:37:36,580 ERROR [io.smallrye.graphql] (default task-1) SRGQL012000: Data Fetching Error: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: gov.utah.health.model.user.AppUser.roles, could not initialize proxy - no Session
	at org.hibernate@5.3.23.Final//org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:602)
	at org.hibernate@5.3.23.Final//org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217)
	at org.hibernate@5.3.23.Final//org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:581)
	at org.hibernate@5.3.23.Final//org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:148)
	at org.hibernate@5.3.23.Final//org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:188)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.execution.datafetcher.helper.AbstractHelper.recursiveTransformCollection(AbstractHelper.java:205)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.execution.datafetcher.helper.AbstractHelper.recursiveTransform(AbstractHelper.java:72)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.execution.datafetcher.helper.FieldHelper.transformResponse(FieldHelper.java:32)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.execution.datafetcher.PropertyDataFetcher.get(PropertyDataFetcher.java:36)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:270)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:203)
	at io.smallrye.graphql@4.8//graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:60)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.completeValueForObject(ExecutionStrategy.java:646)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.completeValue(ExecutionStrategy.java:438)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.completeField(ExecutionStrategy.java:390)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.lambda$resolveFieldWithInfo$1(ExecutionStrategy.java:205)
	at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680)
	at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658)
	at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094)
	at io.smallrye.graphql@4.8//graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:204)
	at io.smallrye.graphql@4.8//graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:60)
	at io.smallrye.graphql@4.8//graphql.execution.Execution.executeOperation(Execution.java:165)
	at io.smallrye.graphql@4.8//graphql.execution.Execution.execute(Execution.java:104)
	at io.smallrye.graphql@4.8//graphql.GraphQL.execute(GraphQL.java:557)
	at io.smallrye.graphql@4.8//graphql.GraphQL.parseValidateAndExecute(GraphQL.java:482)
	at io.smallrye.graphql@4.8//graphql.GraphQL.executeAsync(GraphQL.java:446)
	at io.smallrye.graphql@4.8//graphql.GraphQL.execute(GraphQL.java:377)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.execution.ExecutionService.execute(ExecutionService.java:123)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.servlet.ExecutionServlet.handleInput(ExecutionServlet.java:93)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.servlet.ExecutionServlet.handleInput(ExecutionServlet.java:88)
	at io.smallrye.graphql@4.8//io.smallrye.graphql.servlet.ExecutionServlet.doPost(ExecutionServlet.java:78)
	at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:523)
	at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
	at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at org.wildfly.security.elytron-web.undertow-server@1.9.1.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
	at org.wildfly.security.elytron-base@1.17.1.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
	at org.wildfly.security.elytron-base@1.17.1.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
	at org.wildfly.security.elytron-base@1.17.1.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
	at org.wildfly.security.elytron-web.undertow-server@1.9.1.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.core@2.2.12.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.core@2.2.12.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at org.wildfly.security.elytron-web.undertow-server-servlet@1.9.1.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
	at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
	at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
	at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:280)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
	at org.wildfly.extension.undertow@25.0.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:260)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79)
	at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100)
	at io.undertow.core@2.2.12.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
	at io.undertow.core@2.2.12.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
	at org.jboss.xnio@3.8.4.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
	at java.base/java.lang.Thread.run(Thread.java:829)

This might sound familiar. Issue #71 and Issue #95 are both similar. #95 seems like it should have solved this back with the v1.0.1 release. The exception seems to be a little different, though.

Now if I tell JPA to eager-load rather than lazy-load the AppRole set, of course it works, but then it’s always loading all data whether it’s needed or not. I can also avoid an exception if I set <property name="hibernate.enable_lazy_load_no_trans" value="true"/> in persistence.xml, but that’s just hitting the database every time the roles are accessed, not suitable for production code.

I’ve tried annotating alternately my @GraphQLApi public class AppUserService and the individual @Query("user") public AppUser getUser(...) method with javax.transaction.Transactional, but that doesn’t seem to have made any difference. The getUser() method finishes executing and I assume the transaction ends there before reaching the graphql code where the exception is thrown.

Is there something I’m missing?

Edit: I also just gave it a try with smallrye-graphql v1.3.5 (latest) and got the same error.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 18 (8 by maintainers)

Most upvoted comments

@phillip-kruger: Hah, you where a bit faster, but GitHub didn’t tell me 😉