Issue
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
Solution
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);
Answered By - Anuska