Home > Software design >  Injecting a SessionScope bean in Controller not working
Injecting a SessionScope bean in Controller not working

Time:09-22

I am having trouble setting an attribute value ie. shortname to a SessionScope bean in Spring Boot.

Here is my class:

    import java.util.Map;

    public class LdapUser {
        private String shortname = "";
        private Map<String,String> token = null;
        private String id = "";
    
    public LdapUser() {
           
        }
    
        public String getshortname() {
            return shortname;
        }
    
        public void setshortname(String shortname) {
            this.shortname = shortname;
        }
... remaining geters and setters

My Bean definition is here:

import xxx.controllers.SwitchController;
import xxx.isim.LdapUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;

@Configuration
public class RestTemplateClient {

    Logger logger = LoggerFactory.getLogger(SwitchController.class);

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public LdapUser sessionScopedLdapUser() {
        logger.info("LdapUser bean instance created");
        return new LdapUser();
    }
}

I am using the Bean in a Controller:

import xxx.errors.IsimConnectionException;
import xxx.isim.IsimConnection;
import xxx.isim.LdapUser;
import xxx.services.IsimRestApiService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.security.Principal;

@Controller
public class HomeController {

    private static final Logger log = LoggerFactory.getLogger(HomeController.class);

    @Autowired
    IsimRestApiService isimConn;

    @Resource(name = "sessionScopedLdapUser")
    LdapUser sessionScopedLdapUser;

    @RequestMapping("/")
    public String index(Principal principal) throws IsimConnectionException {
        Authentication authentication = (Authentication) principal;

        /

        if ((authentication.getPrincipal() != null) && (authentication.isAuthenticated())) {
            // set the shortname for the session
            String shortname = (String)authentication.getPrincipal();
            sessionScopedLdapUser.setshortname(shortname); //<-----

My Bean's value for shortname remains null after the line with the arrow even though I correctly get the shortname String value and that one is not null. Can you please point me out what am I doing wrong when setting the bean attribute values. I followed the example here for SessionScope Beans

Update: I also tried to use autowired instead of @Resource(name = "sessionScopedLdapUser") but the value still remains null after executing sessionScopedLdapUser.setshortname(shortname);

 @Autowired
 LdapUser sessionScopedLdapUser

Also in the log I can see the LdapUser bean instance is created three times. How is that possible?

2021-09-21 10:55:55,469 INFO  [http-nio-8080-exec-4] xxx.config.RestTemplateClient: LdapUser bean instance created
2021-09-21 10:57:05,247 INFO  [http-nio-8080-exec-4] xxx.config.RestTemplateClient: LdapUser bean instance created
2021-09-21 10:58:08,401 INFO  [http-nio-8080-exec-4] xxx.config.RestTemplateClient: LdapUser bean instance created

The ideas is to have one bean per HTTP session. I am really confused and would appreciate some hints. I was reading this article and maybe that is because I am trying to inject a Session Scope bean to a Singletone bean.

My file structure is:

xxx
---auth
---config
   --- RestRemplateClient
---controllers
   --- HomeController
---errors
---isim
   --- LdapUser
---services
Mainapp

CodePudding user response:

Thanks to @M. Deinum I was able to figure it out. I was looking at the field value in the debugger and that one was always null since I was looking the proxy and not the real object.

Here is the code that injects a session scoped bean in the @Controller class. It also works correctly and in the same way in the @Service class.

public class LdapUser {
    private String shortname = "";
    private Map<String,String> token = new HashMap<>();
    private String id = "";

    public LdapUser() {
        this.shortname = shortname;
        this.token = token;
        this.id = id;
    }


    public String getshortname() {
        return shortname;
    }

    public void setshortname(String shortname) {
        this.shortname = shortname;
    }
 ... other getters and setters

My bean configuration class:

@Configuration
public class RestTemplateClient {

Logger logger = LoggerFactory.getLogger(SwitchController.class);

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

@Bean
@SessionScope
public LdapUser sessionScopedLdapUser() {
    logger.info("LdapUser bean instance created at "  LocalDateTime.now());
    return new LdapUser();
}

}

My controller class:

@Controller
public class HomeController {
private static final Logger log = LoggerFactory.getLogger(HomeController.class);

@Autowired
IsimRestApiService isimConn;

@Autowired
LdapUser sessionScopedLdapUser;

@RequestMapping("/")
public String index(Principal principal) throws IsimConnectionException {
    Authentication authentication = (Authentication) principal;

    //System.out.println("******* USER IS "   authentication.getPrincipal());

    if ((authentication.getPrincipal() != null) && (authentication.isAuthenticated())) {
        // set the shortname for the session
        String shortname = (String)authentication.getPrincipal();

        sessionScopedLdapUser.setshortname(shortname);

CodePudding user response:

You can specify your configurations as below:-

import org.springframework.context.annotation.Scope;
import java.time.LocalDateTime;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class LdapUser {

    private String shortName = "LdapUser Session Scope";
// other properties
    
    public LdapUser() {
        System.out.println("LdapUser SessionScope Constructor Called at " LocalDateTime.now());
    }

    public String getShortName() {
        return shortName;
    }

    public void setShortName(String shortName) {
        this.shortName = shortName;
    }
}

In configuration:

@Configuration
public class RestTemplateClient {

    Logger logger = LoggerFactory.getLogger(SwitchController.class);

    @Autowired
    private LdapUser ldapUser;

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public void setLdapUser(LdapUser ldapUser) {
    this.ldapUser = ldapUser;
    }

    public LdapUser getLdapUser() {
    return ldapUser;
    }
}

and into your controller:-

@Controller
public class HomeController {
// Other Codes

@Autowired
private RestTemplateClient restTemplateClient;

private static final Logger log = LoggerFactory.getLogger(HomeController.class);

    @Autowired
    IsimRestApiService isimConn;

@RequestMapping("/")
    public String index(Principal principal) throws IsimConnectionException {
        Authentication authentication = (Authentication) principal;

        /

        if ((authentication.getPrincipal() != null) && (authentication.isAuthenticated())) {
            // set the shortname for the session
            String shortname = (String)authentication.getPrincipal();
restTemplateClient.getLdapUser().setShortName("LdapUser Session Scope Updated");
// .... Other codes
}
}
}
  • Related