No curso anterior, quando os usuários ainda não tinham perfis, implementei a classe Usuario sem o EAGER na anotação ManyToMany:
@ManyToMany
private List<Perfil> perfis = new ArrayList<>();
Imaginei que esse seria o mais correto, para não trazer sempre os Perfis mesmo em casos em que não fossem necessários, e que além disso não teria problemas porque os perfis seriam buscados no Banco de Dados com um SELECT extra. No pior dos casos seria apenas uma penalidade de performance.
Para minha surpresa, agora que mudei a SecurityConfigurations para exigir roles, e os perfis estão sendo efetivamente usados para restringir acessos, passei a tomar o seguinte erro ao tentar deletar um Topico:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ljpeixoto.forum.modelo.Usuario.perfis, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:614) ~[hibernate-core-5.6.7.Final.jar:5.6.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218) ~[hibernate-core-5.6.7.Final.jar:5.6.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:591) ~[hibernate-core-5.6.7.Final.jar:5.6.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.6.7.Final.jar:5.6.7.Final]
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387) ~[hibernate-core-5.6.7.Final.jar:5.6.7.Final]
at org.springframework.security.authentication.AbstractAuthenticationToken.<init>(AbstractAuthenticationToken.java:58) ~[spring-security-core-5.6.2.jar:5.6.2]
at org.springframework.security.authentication.UsernamePasswordAuthenticationToken.<init>(UsernamePasswordAuthenticationToken.java:68) ~[spring-security-core-5.6.2.jar:5.6.2]
at com.ljpeixoto.forum.config.security.AutenticacaoViaTokenFilter.autenticarCliente(AutenticacaoViaTokenFilter.java:42) ~[classes/:na]
Tentei de várias maneiras evitar colocar o EAGER em perfis, pois mesmo que se argumente que no caso específico a melhor opção seria o EAGER mesmo, creio que essa seja uma situação costumeira - um relacionamento em que uma propriedade do tipo lista seja recuperada apenas sob demanda - mas não consegui - sempre dá essa exceção, com a mensagem de erro dizendo que não há uma session aberta. Anotei a classe AutenticacaoViaTokenFilter e até o método doFilterInternal com a anotação @Transactional, mas o erro permaneceu. No meu entendimento, se usei o @Transactional o Spring deveria abrir uma Session antes de iniciar o método, e mantê-lo aberto até o fim da execução, não ?
Qual seria a maneira correta de fazer o JPA recuperar a lista de Perfis sob demanda (ou seja, com comportamento LAZY) ?