org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: in Spring boot

1.2k views Asked by At

In our case there are two entities User and UserRole and relationship between those two entity are one to many relationship. We perform some operation like we get the user data using Hibernate and after that we get the UserRole from User entity lazily

public class User {

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<UserRole> userRoles;
}

public class UserRole {

    @ManyToOne
    User user;

    String name;
}

public String getUserRoleName(Long userId) {

    User user = repository.findById(userId);

    List<UserRole> userRoles = user.getUserRoles();
       
    String name = userRoles.stream().map(obj -> obj.getName()).collect(Collectors.joining(", "));

    return name;
}

In above code we get the below exception

Runtime error message is:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
co.entity.User.userRoles, could not initialize proxy - no Session
  at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
  at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
  at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
  at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
  at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387)
  at java.base/java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators.java:1821)
  at java.base/java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408)
  at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:483)
  at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
  at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
  at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
  at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
  at co.service.UserService.getUserRoleName(UserService.java:20)
  at co.controller.UserController.getUserRoleName(UserController.java:10)
  at jdk.internal.reflect.GeneratedMethodAccessor193.invoke(Unknown Source)
  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.base/java.lang.reflect.Method.invoke(Method.java:566)
  at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
  at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) 
  at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
  at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
  at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
  at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
  at java.base/java.lang.Thread.run(Thread.java:829)

We have used the @Transactional annotation to solve this issue.

1

There are 1 answers

0
Andrei Lisa On

The stack trace are telling you all that you need to know: You are trying to access the roles after the session is closed, and as a result, the code throws a LazyInitializationException.

You have multiple choices to fix it:

Declare Fetch Type as Eager:

  @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
  private List<UserRole> userRoles;

But in my opinion EAGER fetch type is not a good idea, because it tells JPA to always fetch the data, even when this data is not necessary.

Second solution is to use JOIN FETCH directive in JPQL

Declare a custom query into repository and then you can fetch it

Instead of writing

User user = repository.findById(userId); // default method from repository

Do it (create custom method in repository something like this): Repository:

@Query("SELECT u FROM User u JOIN FETCH u.roles WHERE u.userId = :userId")
List<User> findUserAndUserRolesByUserId(@Param("userId") Long userId)

And then in your method replace:

User user = repository.findById(userId);

TO:

User user = repository.findUserAndUserRolesByUserId(userId);

More ways to fix it you can find here also here on stackoverflow are many Q/A about this topic because it is one of the most popular when is working with hibernate as ORM.