EJB 3.1 - Inject Session Scope Pojo - java

Using: EJB 3.1, JBoss AS 7, RestEasy.
I have a session scoped bean which I want to user to store user informations for the session.
import java.io.Serializable;
import javax.enterprise.context.SessionScoped
#SessionScoped
public class LoggedInUser implements Serializable {
private String id;
...
}
If the user open my web application a filter extract header informations (application runs behind a webseal) which contains a user identification. I need to create a logged in user object (see LoggedInUser above) there (after calling ldap). Afterwards I want to inject this LoggedInUser object in different #Stateless Beans, but LoggedInUser is always "empty" (members are null).
Inject sample:
#Path("/country")
#Stateless
public class CountryController extends AbstractController {
#Inject
private Logger LOGGER;
#Inject
private LoggedInUser loggedInUser;
//#Inject dont work too..
//private Instance<LoggedInUser> loggedInstance
What do Im wrong?

Judging by the comment and the question - you need some help with EJB concepts.
#SessionScoped beans are beans that have one instance per session. Every #Inject with bean like that during one session will reference the same object. That's it however - if you want your bean to contain some information specific to that session, you will need to put it there yourself, using setters or other methods like you would do in every normal Java class.

Related

#Inject and #PostConstruct not working in singleton pattern

I have a class as below:
public class UserAuthenticator {
private static UserAuthenticator authenticator =
#Inject
private UserRepository userRepository;
#PostConstruct
public void init() {
List<User> allUsers = userRepository.findAll();
for (User user : allUsers) {
users.put(user.getEmail(), user.getPassword());
serviceKeys.put(user.getServiceKey(), user.getEmail());
}
}
public static UserAuthenticator getInstance() {
if (authenticator == null) {
authenticator = new UserAuthenticator();
}
return authenticator;
}
}
When I call
UserAuthenticator authenticator = UserAuthenticator.getInstance();
init() method isn't called and userRepository is null
My web application run in JBOSS EAP 6.3.
How is this caused and how can I solve it?
In a Java EE application, don't think in singletons. That's only recipe for trouble and confusion. Instead, think in "just create one". Tell the Java EE container to just create only one instance of the specified class, application wide, and obtain the instance via the facility offered by the Java EE container. Your concrete problem is caused because you're manually creating an instance of the class using new operator without manually performing the injection and post construct call like as the technical correct but conceptually wrong example below:
authenticator = new UserAuthenticator();
authenticator.userRepository = new UserRepository();
authenticator.init();
In other words, you incorrectly expected that the new operator magically recognizes the bean management and dependency injection related annotations.
The right approach depends on the one you'd like to point out as the responsible for creating and managing the instance of the specified class. If it's CDI, then just tell it to create only one managed bean instance of the backing bean class, application wide, using #Named #ApplicationScoped.
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;
#Named
#ApplicationScoped
public class UserAuthenticator {}
It will be created just once and be available via #Inject as below in any other Java EE managed artifact (read: in any other class annotated with #Named, #Stateless, #ManagedBean, #WebServlet, #WebListener, #WebFilter, #Path, etc..):
#Inject
private UserAuthenticator userAuthenticator;
If you're absolutely positive that you need a static method to grab the current CDI managed bean instance of a given backing class, then you should be obtaining it via BeanManager as below instead of manually constructing the instance (assuming Java EE 7 / CDI 1.1 available):
#SuppressWarnings("unchecked")
public static <T> T getCurrentInstance(Class<T> beanClass) {
BeanManager beanManager = CDI.current().getBeanManager();
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(beanClass));
return (T) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
}
Usage:
UserAuthenticator userAuthenticator = YourCDIUtil.getCurrentInstance(UserAuthenticator.class);
// ...
See also:
Java singleton class vs JSF application scoped managed bean - differences?
Java EE 6 and Singletons
Well i think you shouldn't explictly call UserAuthenticator.getInstance() but to define the UserAuthenticator for example as #ApplicationScoped and get the instance via DI provided by your app server (#Inject).
UserAuthenticator should be then initialized properly.
The #PostConstruct method will not be invoked until you do some action on that class (ex: call some methods

JSF : Passing an Object from one backing-bean to another backing-bean

I am trying to figure out a solution for a small problem I have encountered whilst developing a small application. I am trying to pass an object created within one backing-bean and then later using that same object I created within another backing-bean. However, I would not like to make these backing-beans #SessionScoped, and preferably not use the #ManagedBean as I am using CDIfor my JavaEE application.
Is there anyway I could do this using CDI annotations and injecting one backing-bean to another and then have the ability to access that object previously created?
As an example, refer to the below beans:
#Named
#ViewScoped
public RegisterController implements Serializable {
User user = new User();
// Getter and Setter methods which are populated by the JSF page
}
Get Object User created within the above bean and use it within the controller below:
#Named
#ViewScoped
public PaymentController implements Serializable {
#Inject RegisterController registerController; // Injecting bean
registerController.getUser().getName(); //this is null when I try access the properties of the object 'User'. I am assuming this is because #ViewScoped annotated on the 'RegisterController' class?
// I would like to use the User object created in 'RegisterController' here an access properties etc...
}
Could I use the #Inject annotation offered by the CDI?
UPDATE
Ok, so I have got the above working when I annotate the RegisterController with the SessionScoped annotation, however I do not want this Bean annotated SessionScoped as I will probably run into further implications down the track, such as pre-population of fields, etc... Any ideas how to implement this any other way?
Well, #ViewScoped is too short to the purpose and #SessionScoped is too long. Then why not use #ConversationScoped?
See here.
you can use in RegistrationController:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user", user);
and in PaymentController:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("user");
this is very useful, you can save the objects you want in the map.

JSF 2 Spring XRebel Huge session

I recently installed the XRebel plugin, which allows you to see current session size.
I discovered, that the session instantly gets to 10 mb on first page load(initialization of the auth session bean.).
To my setup:
I am using JSF 2.2, Spring 4 and Hibernate 4.
DAO Layer > Service Layer > Managed Bean
DAO Layer
#Named
#Singleton
#Repository
public class UserDao extends BaseDao<User>
{
...
}
Service Layer
#Service
#Named
#Singleton
public class UserService extends BaseService<User>
{
#Autowired
private UserDao dao;
...
}
My auth session bean, that gets loaded on first page load
#Named
#Component
#Scope("session")
public class Auth implements Serializable
{
#Autowired
private UserService userService;
...
}
In my applicationContext.xml I am using
<context:component-scan base-package="com.mypackage" />
This is a general issue I have when I autowire service beans in my session beans.
The Userservice only contains methods to retreive, save and delete user objects, there is no ArrayList containing users or anything else.
I have two #Autowired Services in my auth bean - UserService and SessionService.
If I commment out UserService, SessionService will reach the same size. If I comment out both there is a "DestructionCallbackBindingListener" from "org.springframework.web.context.request.ServletRequestAttribute..." that reaches 8mb instantly.
What am I doing wrong? How do I decrease the session size ?
I gladly accept any help.
Here is an image of XRebel showing that the userService takes about 8mb size in session. http://i.stack.imgur.com/TBXx3.png
Looking at XRebel, it seems that the beanFactory is saved in the user session.
I posted in the official forums regarding XRebel. This is the answer I received.
Indeed, the beanFactory is reachable from the session, through the
CGLIB proxy. We may need to improve to how we recognize objects that
are shared or should not be considered part of the session.
We try to show how much memory each session takes, but Spring
beanFactories are of course shared between sessions usually.
Often the fact that we filter out transient fields from the session
is enough, but we’ll take a look at the CGLIB/Spring proxies to see
how we can filter them out by a general rule or maybe we can just add
specific Spring classes to an ignore list.
In short: The beanfactory can be Ignored when looking at session size, optionally, if possible mark the autowired services transient.
Indeed you can ignore it mentally for now or if it’s possible then
yes, making the variables transient would exclude them.

Why Initialization is not required in EJB?

I am new to the Struts2 framework and to EJB as well. I have a class LoginDAO which implements checkUser method of an interface LoginDAOLocal. I don't understand why I see different behavior for the following scenarios:
If I use an EJB (LoginDAO is stateless session bean) as follows, method call works perfectly without any error.
#EJB
private LoginDAOLocal loginDao;
loginDao.checkUser(userName,password);
If I use Struts2 as follows, it gives a Null pointer exception for the method call.
public class LoginAction extends ActionSupport {
// Getters setters for userName and password)
private LoginDAOLocal loginDao;
loginDao.checkUser(this.userName,this.password);
}
If I use a simple Java application (no EJB or Struts2), the method call creates a compile time error saying loginDao is not initialized
public static void main(String[] args) {
LoginDAOLocal loginDao;
loginDao.checkUser(userName,password);
}
Can someone explain why this different behavior ?
Without getting too much into the Java EE spec: EJBs are managed by an EJB container that exists in J2EE servers (JBoss \ Websphere etc..). The container takes control of bean lifecycle and is responsible for creating \ destroying beans according to the application needs.
When running out of container (simple java application) your beans won't get initialized and you don't have a JNDI context to get beans from, even if you add #EJB annotation to the field member.
We can say that there are two ways to manage the beans, using the container (managed by the container), or by another component (managed by a servlet, listener or filter).
Using components managed by the container, the container injects the references. e.g.:
#WebServlet("/test")
public class MyServlet extends HttpServlet {
#Resource(lookup = "jdbc/TestDS")
private DataSource testDS;
}
By contrast, a component managed by a bean, e.g.:
#Namespace("/User")
#ResultPath(value = "/")
#Result(name = "success", location = "pages/login.jsp")
public class LoginAction extends ActionSupport {
}
is managed by the filter org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter. The latter should be responsible for performing dependency injection. Spring, for example, takes care of injecting all necessary dependencies.

Spring store object in session

I would like to implement a shopping cart with Spring, so I need to save an object Cart ( which has attributes like products, paymentType and deliveryType ) in session. I've tried to create it with bean and attribute "scope" set to "session", but it just doesn't work, should I use some additional annotations in my controller or Cart class? Any example usage would be really helpful :-) Thanks in advance.
#Component
#Scope("session")
public class Cart { .. }
and then
#Inject
private Cart cart;
should work, if it is declared in the web context (dispatcher-servlet.xml). An alternative option is to use the raw session and put your cart object there:
#RequestMapping(..)
public String someControllerMethod(HttpSession session) {
session.setAttribute(Constants.CART, new Cart());
...
Cart cart = (Cart) session.getAttribute(Constants.CART);
}
If you are injecting the shopping cart directly into your controller, the issue is likely happening because your controller is singleton scoped (by default), which is wider scope than the bean you're injecting. This excellent article gives an overview of four approaches to exactly what you're trying to do: http://richardchesterwood.blogspot.co.uk/2011/03/using-sessions-in-spring-mvc-including.html.
Here's a quick summary of solutions:
Scope the controller to session scope (use #scope("session") on controller level) and just have a shopping cart instance in the controller.
Scope the controller to request and have session-scoped shopping cart injected.
Just use the session directly - kind of messy, IMO.
Use Spring's annotation <aop:scoped-proxy/>.
All of the methods have their pros and cons. I usually go with option 2 or 4. Option 4 is actually pretty simple and is the only approach I have seen documented by Spring.
You just need to add Scope annotation as below with session and proxy mode
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart implements Serializable{
}
Where ever you need to use shopping cart object, you can autowire it
#Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
Logger logger = LoggerFactory.getLogger(ShoppingCartServiceImpl.class);
#Autowired
ShoppingCart shoppingCart;
}
Disclosure: I have developed a sample project, which uses spring MVC, angularJS and bootstrap that demonstrate Spring Session scope -
https://github.com/dpaani/springmvc-shoppingcart-sample
try to autowired HttpSession and spring will injects in a proxy to the HttpSession
#Autowired
private HttpSession httpSession;

Categories

Resources