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
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;
}
}
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");
}
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.
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.
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.