How to fix Hibernate LazyInitializationException: failed to lazily initialize a collection of roles, could not initialize proxy - no Session

JavaSpringHibernateSpring MvcSpring Security

Java Problem Overview


In the custom AuthenticationProvider from my spring project, I am trying read the list of authorities of the logged user, but I am facing the following error:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.horariolivre.entity.Usuario.autorizacoes, could not initialize proxy - no Session
	at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
	at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
	at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
	at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
	at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266)
	at com.horariolivre.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:45)
	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
	at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:744)

Reading other topics from here in StackOverflow, I understand this happens due the way this type of atribute is handled by the framework, but i can't figure out any solution for my case. Someone can point what i am doing wrong and what I can do to fix it?

The code of my Custom AuthenticationProvider is:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
	
	@Autowired
	private UsuarioHome usuario;
	
	public CustomAuthenticationProvider() {
		super();
	}

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		System.out.println("CustomAuthenticationProvider.authenticate");
		
		String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        
        Usuario user = usuario.findByUsername(username);
                
        if (user != null) {
        	if(user.getSenha().equals(password)) {
        		List<AutorizacoesUsuario> list = user.getAutorizacoes();
        		
        		List <String> rolesAsList = new ArrayList<String>();
        	    for(AutorizacoesUsuario role : list){
        	        rolesAsList.add(role.getAutorizacoes().getNome());
        	    }
        	    
        	    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        	    for (String role_name : rolesAsList) {
        	        authorities.add(new SimpleGrantedAuthority(role_name));
        	    }
        	    
	            Authentication auth = new UsernamePasswordAuthenticationToken(username, password, authorities);
	            return auth;
        	}
        	else {
        		return null;
        	}
        } else {
        	return null;
        }
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return authentication.equals(UsernamePasswordAuthenticationToken.class);
	}
	
}

My Entity classes are:

UsuarioHome.java

@Entity
@Table(name = "usuario")
public class Usuario implements java.io.Serializable {

	private int id;
	private String login;
	private String senha;
	private String primeiroNome;
	private String ultimoNome;
	private List<TipoUsuario> tipoUsuarios = new ArrayList<TipoUsuario>();
	private List<AutorizacoesUsuario> autorizacoes = new ArrayList<AutorizacoesUsuario>();
	private List<DadosUsuario> dadosUsuarios = new ArrayList<DadosUsuario>();
	private ConfigHorarioLivre config;

	public Usuario() {
	}

	public Usuario(String login, String senha) {
		this.login = login;
		this.senha = senha;
	}

	public Usuario(String login, String senha, String primeiroNome, String ultimoNome, List<TipoUsuario> tipoUsuarios, List<AutorizacoesUsuario> autorizacoesUsuarios, List<DadosUsuario> dadosUsuarios, ConfigHorarioLivre config) {
		this.login = login;
		this.senha = senha;
		this.primeiroNome = primeiroNome;
		this.ultimoNome = ultimoNome;
		this.tipoUsuarios = tipoUsuarios;
		this.autorizacoes = autorizacoesUsuarios;
		this.dadosUsuarios = dadosUsuarios;
		this.config = config;
	}
	
	public Usuario(String login, String senha, String primeiroNome, String ultimoNome, String tipoUsuario, String[] campos) {
		this.login = login;
		this.senha = senha;
		this.primeiroNome = primeiroNome;
		this.ultimoNome = ultimoNome;
		this.tipoUsuarios.add(new TipoUsuario(this, new Tipo(tipoUsuario)));
		for(int i=0; i<campos.length; i++)
			this.dadosUsuarios.add(new DadosUsuario(this, null, campos[i]));
	}

	@Id
	@Column(name = "id", unique = true, nullable = false)
	@GeneratedValue(strategy=GenerationType.AUTO)
	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "login", nullable = false, length = 16)
	public String getLogin() {
		return this.login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	@Column(name = "senha", nullable = false)
	public String getSenha() {
		return this.senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	@Column(name = "primeiro_nome", length = 32)
	public String getPrimeiroNome() {
		return this.primeiroNome;
	}

	public void setPrimeiroNome(String primeiroNome) {
		this.primeiroNome = primeiroNome;
	}

	@Column(name = "ultimo_nome", length = 32)
	public String getUltimoNome() {
		return this.ultimoNome;
	}

	public void setUltimoNome(String ultimoNome) {
		this.ultimoNome = ultimoNome;
	}

	@ManyToMany(cascade=CascadeType.ALL)
	@JoinTable(name = "tipo_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_tipo") })
	@LazyCollection(LazyCollectionOption.TRUE)
	public List<TipoUsuario> getTipoUsuarios() {
		return this.tipoUsuarios;
	}

	public void setTipoUsuarios(List<TipoUsuario> tipoUsuarios) {
		this.tipoUsuarios = tipoUsuarios;
	}

	@ManyToMany(cascade=CascadeType.ALL)
	@JoinTable(name = "autorizacoes_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_autorizacoes") })
	@LazyCollection(LazyCollectionOption.TRUE)
	public List<AutorizacoesUsuario> getAutorizacoes() {
		return this.autorizacoes;
	}

	public void setAutorizacoes(List<AutorizacoesUsuario> autorizacoes) {
		this.autorizacoes = autorizacoes;
	}

	@ManyToMany(cascade=CascadeType.ALL)
	@JoinTable(name = "dados_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_dados") })
	@LazyCollection(LazyCollectionOption.TRUE)
	public List<DadosUsuario> getDadosUsuarios() {
		return this.dadosUsuarios;
	}

	public void setDadosUsuarios(List<DadosUsuario> dadosUsuarios) {
		this.dadosUsuarios = dadosUsuarios;
	}

	@OneToOne
	@JoinColumn(name="fk_config")
	public ConfigHorarioLivre getConfig() {
		return config;
	}

	public void setConfig(ConfigHorarioLivre config) {
		this.config = config;
	}
}

AutorizacoesUsuario.java

@Entity
@Table(name = "autorizacoes_usuario", uniqueConstraints = @UniqueConstraint(columnNames = "id"))
public class AutorizacoesUsuario implements java.io.Serializable {

	private int id;
	private Usuario usuario;
	private Autorizacoes autorizacoes;

	public AutorizacoesUsuario() {
	}

	public AutorizacoesUsuario(Usuario usuario, Autorizacoes autorizacoes) {
		this.usuario = usuario;
		this.autorizacoes = autorizacoes;
	}

	@Id
	@Column(name = "id", unique = true, nullable = false)
	@GeneratedValue(strategy=GenerationType.AUTO)
	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@OneToOne
	@JoinColumn(name = "fk_usuario", nullable = false, insertable = false, updatable = false)
	public Usuario getUsuario() {
		return this.usuario;
	}

	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	@OneToOne
	@JoinColumn(name = "fk_autorizacoes", nullable = false, insertable = false, updatable = false)
	public Autorizacoes getAutorizacoes() {
		return this.autorizacoes;
	}

	public void setAutorizacoes(Autorizacoes autorizacoes) {
		this.autorizacoes = autorizacoes;
	}

}

Autorizacoes.java

@Entity
@Table(name = "autorizacoes")
public class Autorizacoes implements java.io.Serializable {

	private int id;
	private String nome;
	private String descricao;

	public Autorizacoes() {
	}

	public Autorizacoes(String nome) {
		this.nome = nome;
	}

	public Autorizacoes(String nome, String descricao) {
		this.nome = nome;
		this.descricao = descricao;
	}

	@Id
	@Column(name = "id", unique = true, nullable = false)
	@GeneratedValue(strategy=GenerationType.AUTO)
	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "nome", nullable = false, length = 16)
	public String getNome() {
		return this.nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	@Column(name = "descricao", length = 140)
	public String getDescricao() {
		return this.descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}
}

Full project available on github

--> https://github.com/klebermo/webapp_horario_livre

Java Solutions


Solution 1 - Java

You need to either add fetch=FetchType.EAGER inside your ManyToMany annotations to automatically pull back child entities:

@ManyToMany(fetch = FetchType.EAGER)

A better option would be to implement a spring transactionManager by adding the following to your spring configuration file:

<bean id="transactionManager"
	class="org.springframework.orm.hibernate4.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven />

You can then add an @Transactional annotation to your authenticate method like so:

@Transactional
public Authentication authenticate(Authentication authentication)

This will then start a db transaction for the duration of the authenticate method allowing any lazy collection to be retrieved from the db as and when you try to use them.

Solution 2 - Java

The best way to handle the LazyInitializationException is to use the JOIN FETCH directive for all the entities that you need to fetch along.

Anyway, DO NOT use the following Anti-Patterns as suggested by some of the answers:

Sometimes, a DTO projection is a better choice than fetching entities, and this way, you won't get any LazyInitializationException.

Solution 3 - Java

Adding following property to your persistence.xml may solve your problem temporarily

<property name="hibernate.enable_lazy_load_no_trans" value="true" />

As @vlad-mihalcea said it's an antipattern and does not solve lazy initialization issue completely, initialize your associations before closing transaction and use DTOs instead.

Solution 4 - Java

I too had this problem when I was doing unit Testing. A very Simple Solution to this problem is to use @Transactional annotation which keeps the session open till the end of the execution.

Solution 5 - Java

The reason is that when you use lazy load, the session is closed.

There are two solutions.

  1. Don't use lazy load.

    Set lazy=false in XML or Set @OneToMany(fetch = FetchType.EAGER) In annotation.

  2. Use lazy load.

    Set lazy=true in XML or Set @OneToMany(fetch = FetchType.LAZY) In annotation.

    and add OpenSessionInViewFilter filter in your web.xml

Detail See my post.

https://stackoverflow.com/a/27286187/1808417

Solution 6 - Java

Your Custom AuthenticationProvider class should be annotated with the following:

> @Transactional

This will make sure the presence of the hibernate session there as well.

Solution 7 - Java

For those who have this problem with collection of enums here is how to solve it:

@Enumerated(EnumType.STRING)
@Column(name = "OPTION")
@CollectionTable(name = "MY_ENTITY_MY_OPTION")
@ElementCollection(targetClass = MyOptionEnum.class, fetch = EAGER)
Collection<MyOptionEnum> options;

Solution 8 - Java

You can use hibernate lazy initializer.

Below is the code you can refer.
Here PPIDO is the data object which I want to retrieve

Hibernate.initialize(ppiDO);
if (ppiDO instanceof HibernateProxy) {
    ppiDO = (PolicyProductInsuredDO) ((HibernateProxy) ppiDO).getHibernateLazyInitializer()
        .getImplementation();
    ppiDO.setParentGuidObj(policyDO.getBasePlan());
    saveppiDO.add(ppiDO);
    proxyFl = true;
}

Solution 9 - Java

First of all I'd like to say that all users who said about lazy and transactions were right. But in my case there was a slight difference in that I used result of @Transactional method in a test and that was outside real transaction so I got this lazy exception.

My service method:

@Transactional
User get(String uid) {};

My test code:

User user = userService.get("123");
user.getActors(); //org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role

My solution to this was wrapping that code in another transaction like this:

List<Actor> actors = new ArrayList<>();
transactionTemplate.execute((status) 
 -> actors.addAll(userService.get("123").getActors()));

Solution 10 - Java

A common practice is to put a @Transactional above your service class.

@Service
@Transactional
public class MyServiceImpl implements MyService{
...
}

Solution 11 - Java

There are cases where you don't need to put @Transactional annotation to your service method, like integration testing where you can just add @Transactional to your test method. You can get org.hibernate.LazyInitializationException when testing a method that just selects from database, which does not need to be transactional. For example, when you try to load an entity class which has a lazy fetch relation like below may cause this :

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Item> items;

so you add the @Transactional annotation to only to the test method.

@Test
@Transactional
public void verifySomethingTestSomething()  {

Solution 12 - Java

I believe rather than enabling eager fetch, it make sense to re-initialise your entity where its needed to avoid LazyInitializationException exception

Hibernate.initialize(your entity);

Solution 13 - Java

For those using JaVers, given an audited entity class, you may want to ignore the properties causing the LazyInitializationException exception (e.g. by using the @DiffIgnore annotation).

This tells the framework to ignore those properties when calculating the object differences, so it won't try to read from the DB the related objects outside the transaction scope (thus causing the exception).

Solution 14 - Java

Add the annotation

@JsonManagedReference

For example:

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name = "autorizacoes_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_autorizacoes") })
@JsonManagedReference
public List<AutorizacoesUsuario> getAutorizacoes() {
	return this.autorizacoes;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKleber MotaView Question on Stackoverflow
Solution 1 - Javajcmwright80View Answer on Stackoverflow
Solution 2 - JavaVlad MihalceaView Answer on Stackoverflow
Solution 3 - JavaJamaliView Answer on Stackoverflow
Solution 4 - JavaKarthikaSrinivasanView Answer on Stackoverflow
Solution 5 - JavasaneryeeView Answer on Stackoverflow
Solution 6 - JavaBilal Ahmed YaseenView Answer on Stackoverflow
Solution 7 - JavaSasha ShpotaView Answer on Stackoverflow
Solution 8 - JavaMitesh CView Answer on Stackoverflow
Solution 9 - Javavk23View Answer on Stackoverflow
Solution 10 - JavaDebView Answer on Stackoverflow
Solution 11 - JavamcvkrView Answer on Stackoverflow
Solution 12 - JavaPravin BansalView Answer on Stackoverflow
Solution 13 - JavanickshoeView Answer on Stackoverflow
Solution 14 - JavaMauricioView Answer on Stackoverflow