Session scoped bean behaves as Request scope bean - java

I have Session scope bean which behaves as request scope bean.
I'm using it in Singleton bean, and maybe that's why with second request is has null values?
Code which I used to setup the bean:
In singleton:
#Autowired
private MyBean myBean;
MyBean class:
#Component
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public class MyBeanImpl implements MyBean, Serializable {
Configuration:
#Configuration
#ComponentScan(scopedProxy = ScopedProxyMode.INTERFACES, value = { "my.package.with.bean" })
public class ComponentsConfig {
}
MyBean is simple pojo. with getters and setters.
With first request I set values on that bean, with second request in the same class (singleton) I want to read those values, but all values are null. There is no way that something has overrdiden those values.
EDIT
How I make requests - It's just simple browser request, and code which read/writes to my session bean lays in filters.
This is singleton:
#Service
public class SingletonBean {
#Autowired
private MyBean myBean;
// here I save the data to session scoped bean
private void saveUser(LdapContext ctx, String principal) throws NamingException {
Attributes attributes = getAttributes();
myBean.setId("id");
myBean.setName("name");
myBean.setEmail("email");
myBean.setTelNum("123");
myBean.setGroups(Lists.newArrayList("one", "two"));
myBean.setAddress("address");
}
// here I try to read data from session scoped bean:
#Override
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
LdapContextFactory ldapContextFactory) throws NamingException {
// here userInfo will be null
List<String> userInfo = myBean.getGroups();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
for (String role : userInfo ) {
authorizationInfo.addRole(role);
}
return authorizationInfo;
}
}
When user logs in, and he is authenticated, I save his details in session bean. When he tries to open any page method queryForAuthorizationInfo is executed (after chain of filters) and values are null in that object.

Related

How to create a request scoped bean at runtime with spring

I have a spring application and want to create a bean at runtime per request to inject it into another class, just like #Producer for CDI.
My bean is just a simple POJO:
public class UserDetails {
private String name;
// getter / setter ...
public UserDetails(String name) {
this.name = name;
}
}
My producer class looks like this:
#Configuration
public class UserFactory {
#Bean
#Scope("request")
public UserDetails createUserDetails() {
// this method should be called on every request
String name = SecurityContextHolder.getContext()
.getAuthentication().getPrincipal(); // get some user details, just an example (I am aware of Principal)
// construct a complex user details object here
return new UserDetails(name)
}
}
And this is the class where the UserDetails instance should be injected:
#RestController
#RequestMapping(value = "/api/something")
public class MyResource {
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public List<String> getSomething(UserDetails userDetails) {
// the userdetails should be injected here per request, some annotations missing?
// do something
}
}
The problem is that Spring complains at runtime about no default constructor (of course).
Failed to instantiate [UserDetails]: No default constructor found
But this is intended and I want to call my own factory to let it handle the Instantiation.
How can I achieve this? Why is UserFactory never called?
Basically you aren't using your scoped proxy. You cannot inject a scoped proxy into a method, you have to inject it into your controller.
public List<String> getSomething(UserDetails userDetails) { ... }
This will lead to spring trying to create a new instance of UserDetails through reflection, it will not inject your scoped bean. Hence it complains about the fact you need a default no-args constructor.
Instead what you should do is wire the dependency into your controller instead of the controller method.
#RestController
#RequestMapping(value = "/api/something")
public class MyResource {
#Autowired
private UserDetails userDetails;
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public List<String> getSomething() {
// the userdetails should be injected here per request, some annotations missing?
// do something
}
}
The idea is that the UserDetails is a scoped proxy and when used will either use the already present object or create a new one based on the #Bean method.
Additonally, the #Scope annotation in the UserFactory has to be modified as follows in order to work:
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
You're trying to inject a request scoped bean on a singleton bean.
You need to use a proxy for the UserDetails
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
You need a no arguments constructor in class UserDetails.
public class UserDetails {
private String name;
// getter / setter ...
public UserDetails() {
}
public UserDetails(String name) {
this.name = name;
}
}

HttpServletRequest injection on RequestScoped bean CDI

I'm looking for a way in order to inject a #RequestScoped custom class into my #Stateless JAX-RS endpoint:
I want each time the application receives a request my custom class is injected in my JAX-RS endpoint.
Custom class:
#RequestScoped
public class CurrentTransaction {
private String user;
private String token;
#PersistenceContext(name="mysql")
protected EntityManager em;
#Inject HttpServletRequest request;
public CurrentTransaction() {
this.user = request.getHeader("user");
this.token = request.getHeader("token");
}
//getters and setters ...
}
So, I declare my CurrentTransaction class as #RequestScoped in order to be initialized each time a request is received.
In order to do this, I need to access to HttpServletResquest in order to get header parameters.
JAX-RS endpoint:
#Stateless
#Path("/areas")
public class AreasEndpoint {
#PersistenceContext(unitName = "mysql")
protected EntityManager em;
#Inject
protected CurrentTransaction current_user_service;
#POST
#Path("postman")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Authentication
public Response create(AreaRequest request) {
if (this.current_user_service.getUser() == null) {
System.out.println("Go!!!");
return Response.status(Status.FORBIDDEN).build();
} else {
System.out.println("---- user: " + this.current_user_service.getUser());
System.out.println("---- token: " + this.current_user_service.getToken());
}
}
// ...
}
CDI arrive to perform the constructor of CurrentTransaction class. However, HttpServletRequest request field is not initialized (injected).
What am I doing wrong?
A late answer on this one--maybe useful to other readers: dependency injection in CDI is done in the following order:
the constructor is invoked
fields are injected
#PostConstruct annotated method is invoked
The last point is where you want to step in for further initialization that needs access on the injected fields:
#Inject HttpServletRequest request;
public CurrentTransaction() {
// field injection has not yet taken place here
}
#PostConstruct
public void init() {
// the injected request is now available
this.user = request.getHeader("user");
this.token = request.getHeader("token");
}

Access sessionscoped managedbean values in requestscoped/viewscoped managedbean

I'm trying to access an object in my sessioncontroller (sessionscoped bean) from a managedbean. The sessionobject gets created when you log in. Then when I try to persist from the requestscoped bean and I need the login-object from the sessioncontroller but when I debug it's always null.
Bean
#ManagedBean
#ViewScoped
// ??? #RequestScoped
public class BoekingController {
#Inject
private ZoekService zoekService;
#Inject
private BetaalwijzeService betaalwijzeService;
#EJB
private transient BoekingService boekingService;
#ManagedProperty("#{sessionController}")
private SessionController sessionController;
public void init() {
if (betaalwijzeId > 0) {
betaalwijze = betaalwijzeService.findToegestandBetaalwijze(betaalwijzeId);
}
reis = zoekService.findReis(reisId);
if (aantalPersonen > 0) {
instellenBoeking(aantalPersonen, betaalwijze, new Klant(1, "Test", "test#test.be", "test"), reis);
}
}
As you can see I have hardcoded the object myself and persistence works, I just can't get the variable from the sessionController posted below.
SessionController
#SessionScoped
#Named(value = "sessionController")
public class SessionController implements Serializable{
Klant klant;
public Klant getKlant() {
return klant;
}
public void setKlant(Klant klant) {
this.klant = klant;
}
On pages I can access the sessionobject by using:#{sessionController.klantNaam}
The annotation ManagedProperty, as explained in the linked javadoc, should be used to inject a JSF bean annotated with ManagedBean.
Use Inject annotation for injecting a CDI bean.

Modifying a private object property of a managed bean accessed as a managed property from another managed bean

Trying to add a functionality to our JSF 2 application to list active users (who have an active session) and for this I decided to use an application scoped managed bean and store the list of users, adding each by the time of a successful login. Then I would access the active user list (stored on the application scoped managed bean) from a jsf page - only if I could figure out how to resolve the following problem:
The application scoped bean : AppBean.java
#ManagedBean(name = "appBean")
#ApplicationScoped
public class AppBean implements java.io.Serializable {
private List<User> connectedUsers = new ArrayList<User>();
public AppBean() {
}
public List<User> getConnectedUsers() {
return connectedUsers;
}
public void setConnectedUsers(List<User> connectedUsers) {
this.connectedUsers = connectedUsers;
}
}
the Login Bean:
#Named(value = "loginBean")
#SessionScoped
public class LoginBean implements Serializable {
#ManagedProperty("#{appBean}")
private AppBean appBean;
private User userInSession;
public LoginBean() {
}
public String authenticate() {
if (this.authClearsOut()) {
if (appBean != null)
appBean.getConnectedUsers().add(userInSession);
else System.out.println("appBean = null !!!!");
return "/next_screen.xhtml?redirect=true";
}
else return "/login.xhtml?authentication=failed";
}
public AppBean getAppBean() {
return appBean;
}
public void setAppBean(AppBean appBean) {
this.appBean = appBean;
}
}
Now there are two problems here:
1) the appBean is null unless I change line 6 of the LoginBean.java to private AppBean appBean = new AppBean();
2) User userinSession is never added to (List) connectedUsers.
What's wrong here?
The JSF #ManagedProperty annotation works in JSF #ManagedBean only, not in CDI #Named.
Change the LoginBean to be managed by JSF #ManagedBean instead, or change the AppBean beans to be managed by CDI #Named and then use #Inject instead of #ManagedProperty.

How to handle custom autowired objects in Spring 2.5?

I have an old project that I need to integrate with Spring 2.5.x (3.0 is not possible).
I have created a bean, that have to initializate its field userSession by itself:
public class SomeBean {
UserSession userSession;
#PostContrust
public void init() {
HttpSession session = WebContext.current().getSession();
userSession = (UserSession) session.getAttribute("userSession");
}
}
Is it possible to write some kind of autowiring handler that will resolve userSession and pass it for autowiring to Spring, so my bean looks just like:
public class SomeBean {
#Autowire UserSession userSession;
}
and the handler like:
public class AutowireHanlder {
public boolean isCandidate(Class<?> type) {
return type.equals(UserSession.class);
}
public Object resolve(Class<?> type) {
HttpSession session = WebContext.current().getSession();
return (UserSession) session.getAttribute("userSession");
}
}
I would do this using a session-scoped FactoryBean:
public class UserSessionFactoryBean extends AbstractFactoryBean<UserSession> {
#Override
public Class<?> getObjectType() {
return UserSession.class;
}
#Override
protected UserSession createInstance() throws Exception {
HttpSession session = WebContext.current().getSession();
return (UserSession) session.getAttribute("userSession");
}
}
Define UserSessionFactoryBean as a bean:
<bean scope="session" class="com.xyz.UserSessionFactoryBean"/>
... and then you should then be able to autowire UserSession into any other bean.
The complexity here is that UserSessionFactoryBean has to be session-scoped (see docs on bean scopes), since it must return a new value for each HttpSession. This means that any bean it is autowired into must also be session-scoped, otherwise it'll fail. You can get around this restriction using scoped-proxies.

Categories