I am using Hibernate with Spring and i run into this problem failed to lazily initialize a collection : , no session or session was closed using one-to-many relationship I have two tables one is Users & Roles from Users i am trying to get the roles using lazy fetch. The StackTrace
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rep.users.KZ_Users.roleList, no session or session was closed
org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
org.hibernate.collection.PersistentList.iterator(PersistentList.java:115)
com.rep.users.KZ_Users.getAuthorities(KZ_Users.java:137)
org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.createSuccessAuthentication(AbstractUserDetailsAuthenticationProvider.java:186)
org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:165)
org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:120)
org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)
org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:138)
org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:97)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:109)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
i have implemented UserDetails, Serializable in my KZ_Users pojo class and the method that causing the error is
@Override
public Collection<GrantedAuthority> getAuthorities() {
List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
for (Roles roles : roleList) { //<-- ERROR
list.add(new GrantedAuthorityImpl(roles.getRole()));
}
return list;
}
the rolelist is define in KZUser Class. Can any one tell me what was the problem Error is
16:15:01,317 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ReportingPortalV3].[default]] (http-/192.168.1.124:8080-2) JBWEB000236: Servlet.service() for servlet default threw exception: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rep.users.KZ_Users.roleList, no session or session was closed
Thanks in advance.
Keep Spring
specific API separate from your entities. Instead of directly implementing UserDetails
interface in your @Entity
class, extend it (or compose), ie:
public class CurrentUser extends User implements UserDetails {
private final Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
public CurrentUser(User user) {
super(user);
initAuthorities(user);
}
private void initAuthorities(User user) {
if (user.getRoles() == null) {
return;
}
for (Authority role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getAuthority()));
}
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
// implement the rest of UserDetails interface accordingly
}
Also keep initialization of authorities
collection in the constructor. And then:
public class UserDetailsServiceImpl extends UserDetailsService {
@Override
@Transactional(propagation = SUPPORTS, readOnly = true)
public CurrentUser loadUserByUsername(String username)
throws AuthenticationException ,DataAccessException {
ensureNotEmpty(username);
User user = userRepository.findUserWithAuthorities(username);
if (user == null) {
throw new UsernameNotFoundException("Invalid credentials!");
}
return new CurrentUser(user);
}
}
Notice that this way you'll be accessing the roles
collection still within the transaction marked my @Transactional
. Now Spring
can call getAuthorities()
wherewer it needs, and it will work fine, bacuse it's already initialized and connection to database is no longer required.
Always know where your transaction starts and ends .
Depending on your use case, you migh also think about using OpenEntityManagerInViewFilter or OpenEntityManagerInViewInterceptor (or equivalents for native Hibernate
API OpenSessionInViewFilter/Intercetor
), but read about consequences first .
And please tell me that KZ
in the name of the class are not your initiials? If they are, please, please, please don't do that...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.