0

I have a XAuthenticationProvider class which extends AbstractUserDetailsAuthenticationProvider abstract class. And in retrieveUser() method, i want to return the user entity which is lazy loaded from UserSession entity. When I put @Transactional annotation on top of the overriden retrieveUser() method, Hibernate.initialize() threw LazyInitializationException. But I put this annotation to the foo() method in another service(AService), it is working and proxy object successfully converted to entity.

Here is my provider class;

@Component
public class XAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    @Autowired
    private AService aService;

    @Override
    @Transactional
    public UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken token) throws AuthenticationException {

       return aService.foo(); 

    }
}

I inject the provider class in SecurityConfig like this;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private XAuthenticationProvider xAuthenticationProvider;

    @Bean
    @Override
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Collections.singletonList(xAuthenticationProvider));
    }

    public TokenFilter tokenFilter() {
        TokenFilter filter = new TokenFilter(new OrRequestMatcher(                                                                                     
                new AntPathRequestMatcher("*")                                                                                
        ));

        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // REMOVED THIS PART FOR SECURITY REASONS

        http.addFilterBefore(tokenFilter(), UsernamePasswordAuthenticationFilter.class);

    }

}

And this is the foo() method in AService which is annotated by @Service;

//@Transactional
public User foo() {
    UserSession userSession = userSessionRepository.findByStatus(Status.ACTIVE);
    if(userSession!=null) {
        User user = userSession.getUser(); // Lazy loaded

        Hibernate.initialize(user); // Error is thrown from here

        return user;
    } 

    return null;
}

Error thrown is;

org.hibernate.LazyInitializationException: could not initialize proxy [com.turkcell.masrafim.persistence.entity.User] - no Session

So here is my question, i know that Hibernate.initialize() method must be called in an unclosed session to initialize the lazy loaded proxy object, and because of that, I put @Transactional annotation which is org.springframework.transaction.annotation.Transactional on top the method. But why is this annotation is not working on provider class which is a @Component and why is it working in upper level @Service class? What is the difference?

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
elif erdil
  • 39
  • 7
  • 1
    It isn an internal method call, so adding `@Transactional` won't help. Putting it at the service makes in an external method call, which works. This has to do with the way AOP is applied, through proxies, hence only external calls pass through the proxies and not internal method calls (i.e. methods invoked on yourself). – M. Deinum Feb 05 '20 at 12:11
  • Thank you for your reply. But why won't help? Actually i am asking the reason of this situation and how it works. Why only external calls pass through proxies? – elif erdil Feb 05 '20 at 12:51
  • I suggest you read up on what proxies are and how they work. In short a proxy wraps your actual object, to add behavior (like transactions). Once inside that proxy , in your real object, this doesn't happen anymore. – M. Deinum Feb 05 '20 at 12:58
  • 2
    Does this answer your question? [Spring - @Transactional - What happens in background?](https://stackoverflow.com/questions/1099025/spring-transactional-what-happens-in-background). The first answer explains it pretty well. – lugiorgi Feb 05 '20 at 13:02
  • Yes it explains it very well. But i still dont understand that in a controller method, internal method call works fine. I dont even put the @Transactional annotation and reach the lazy loaded proxy object in controller. Why not in this class? Is there something different about controllers or services other than spring security classes? – elif erdil Feb 05 '20 at 13:32
  • I didn't have my answer, why did you close this question? @MarkRoteveel – elif erdil Feb 06 '20 at 11:47

0 Answers0