Can't get viewScoped bean from a SessionScoped bean - java

i would need to get a viewScoped managed bean from a sessionScoped managed bean. I tried firstly using the #ManagedProperty annotation, but i discovered immediately the it does not work and i know why. Secondly i tried to use the following method:
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
PulsantieraBean pulsantiera = (PulsantieraBean) viewMap.get("#{pulsantiera}");
but when i access in debug to the objects, pulsantiera is null and viewMap object contains only another viewScoped managed bean.
The PulsantieraBean class is declared in the following way:
#ViewScoped
#ManagedBean(name = NomeBean.PULSANTIERA)
public class PulsantieraBean extends ControllerBaseBean implements Serializable {
whereas the class in which i do the request is declared as the following
#SessionScoped
#ManagedBean(name = NomeBean.IDF_TAB_IMPORTI)
public class IdfTabImportiBean extends ControllerBaseBean implements Serializable {
I do the request inside a method in which i am sure the viewScoped managed bean PulsantieraBean exists.
Any help would be appreciated.
Thanks,
Marco

#Named(value = "controladorMB")
#SessionScoped
public class ControladorMB implements Serializable {}
call ControladorMB from ListadoFacturasMB
#Named(value = "listadoFacturasMB")
#SessionScoped
public class ListadoFacturasMB implements Serializable {
public void example() {
try {
FacesContext ctx = FacesContext.getCurrentInstance();
ValueExpression vex =ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(), "#{controladorMB}", ControladorMB.class);
ControladorMB gMB = (ControladorMB) vex.getValue(ctx.getELContext());
} catch (Exception e) {
JsfUtil.addErrorMessage(e, "Error: buscarPersonalizado() " + e.getMessage());
}
}
}

Related

How to instantiate a session scoped bean without creating a reference to it?

I have a websocket scoped bean that do something everytime that a new session is created. The problem is that this bean use some observable handlers, it's not called directly, so the bean is never instantiated.
How do I instantiate a websocket scoped bean without making a direct acces to it?
My solution:
Create an interface to use on the components that you want to be initialized:
public interface WebSocketSessionPrematureInitialization {
default void initialize() {}
}
Create a component to initialize all the components that implements the interface:
#Component
#Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketBeanInitializer {
private final List<? extends WebSocketSessionPrematureInitialization> wsInit;
#Autowired
public WebSocketBeanInitializer(List<? extends WebSocketSessionPrematureInitialization> wsInit) {
this.wsInit = wsInit;
}
public void initialize() {
for (WebSocketSessionPrematureInitialization bean : wsInit)
bean.initialize();
}
}
Now you just need to call the initialize() method of the WebSocketBeanInitializer always that a new session is created.

Null pointer when calling #SessionScoped from #RequestScoped

I have a #RequestScoped bean that calls a method from a #SessionScoped one. Inside the last one, I'm getting a NullPointerException when I try to get a java.util.logging.Logger. This doesn't happens if I call the same method from the #SessionScoped directly, not from the other bean...can somebody tell me why is this happening??
The #RequestScoped bean:
#RequestScoped
public class IndexBean {
#Inject
private Auth auth;
public void redirect() throws IOException {
auth.logout();
}
}
And the #SessionScoped one:
#SessionScoped
public class Auth implements Serializable {
public void logout() {
Logger.getLogger(Auth.class.getName()).log(Level.INFO,"Logout");
}
}
The exception arises when I call the redirect() method.

Manually Register Class in CDI Container

I have a group of classes which are instantiated by reflection, hence these are not managed by the CDI container, and no injections are made by the context. My question is, is there any way to register these classes in the CDI context, so the classes get managed by the context?
Bellow, is how I create the classes:
String clazz = "org.myorg.thisIsMyClass";
MyClass myClass = Class.forName(clazz).newInstance(); // myClass instance not managed by CDI
How do I make the instance of myClass managed by the CDI container?
If your classes were registered as bean by the container you can use programmatic lookup to get them easily.
#Inject
#Any
Instance<Object> myBeans;
public Object getMyBeanFromClassName(String className) throws Exception{
Class clazz = Class.forName(className);
return myBeans.select(clazz).get();
}
Et voilĂ .
Following the comments of #AdrianMitev, I finally ended up writing this class which returns an instance of a Managed CDI Bean given its class name (elName) or class type:
public class GetInstance {
public static Object of(String elName) {
BeanManager bm = getBeanManager();
Bean<?> bean = bm.resolve(bm.getBeans(elName));
return bm.getReference(bean, bean.getBeanClass(), bm.createCreationalContext(bean));
}
#SuppressWarnings("unchecked")
public static <T> T of(Class<T> clazz) {
BeanManager bm = getBeanManager();
Bean<?> bean = bm.resolve(bm.getBeans(clazz));
return (T) bm.getReference(bean, bean.getBeanClass(), bm.createCreationalContext(bean));
}
private static BeanManager getBeanManager() {
try {
return (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
} catch (NamingException e) {
e.printStackTrace();
}
return null;
}
}
So, if you have a class like this one:
#Named
public class FooClass {
...
}
You can get an a managed CDI instance using:
FooClass fC = GetInstance.of(FooClass.class);
or using its elName
FooClass fC = (FooClass) GetInstance.of("fooClass");
or you can select the name to use:
#Named(value="CustomFooClassName")
public class FooClass {
...
}
And using:
FooClass fC = (FooClass) GetInstance.of("CustomFooClassName");
The easiest way to do let CDI to manage your class is to use a producer.
public class MyProducers {
#Produces
#RequestScoped //Could be any scope here
#FromReflection //a qualifier to distinguish this Bean of type Object from others. Would be better to have a more specific bean type if all your class come from the same ancestor.
public Object produceMyClass()
{
String clazz = "org.myorg.thisIsMyClass";
Object myObject = Class.forName(clazz).newInstance();
return myObject;
}
}
Somewhere else in your code you can use this producer like this :
#Inject
#FromReflection
Object myBean;
** Edit : adding InjectionPoint usage. **
Now you can enhance your producer by injecting it's InjectionPointin its parameter list. You can then use the metadata of the injection point (i.e qualifier) to dynamically find your class.
First you have to add a field to store the class name in your #FromReflection qualifier :
#Qualifier
#Target({TYPE, METHOD, PARAMETER, FIELD})
#Retention(RUNTIME)
#Documented
public #interface FromReflection {
#Nonbinding String value(); // classname will be store here
}
then you use this info in your producer :
public class MyProducers {
private String extractClassName(InjectionPoint ip) {
for (Annotation annotation : ip.getQualifiers()) {
if (annotation.annotationType().equals(FromReflection.class))
return ((FromReflection) annotation).value();
}
throw new IllegalStateException("No #FromReflection on InjectionPoint");
}
#Produces
#FromReflection
public Object produceMyClass(InjectionPoint ip)
{
String clazzNanme = extractClassName(ip);
Object myObject = Class.forName(clazz).newInstance();
return myObject;
}
}
Note that the produced bean has to be in #Dependent scope, it's a constraint when injecting InjectionPoint in the producer parameters.
You can now inject your bean like that :
#Inject
#FromReflection("org.myorg.thisIsMyClass")
Object myBean;
Now if you want to decide at runtime which class you want to build, you'll have to use the CDI programmatic lookup feature which allow you to create synthetic qualifier.
First create an AnnotationLiteral for your qualifier to be able to instantiate a a new qualifier.
public class FromReflectionLiteral extends AnnotationLiteral<FromReflection> implements FromReflection {
private String value;
public FromReflectionLiteral(String value) {
this.value = value;
}
#Override
public String value() {
return value;
}
}
Then you'll use the Instance<> bean to request for your final bean.
public class ConsumingBean {
#Inject
#Any
Instance<Object> myBeanInstance;
public Object getBeanFor(String className) {
return myBeanInstance.select(new FromReflectionLiteral(className)).get();
}
...
}
Next step would be to use a portable extension...
You can make CDI aware of your instance by not instantiating the bean yourself (as i pointed in your previous post) but to let CDI instantiate the bean. Here is a sample code for that:
InitialContext initialContext = new InitialContext();
BeanManager bm = (BeanManager) initialContext.lookup("java:comp/BeanManager");
//List all CDI Managed Beans and their EL-accessible name
Set<Bean<?>> beans = bm.getBeans(AbstractBean.class, new AnnotationLiteral<Any>() {});
List<Object> beanInstances = new ArrayList<Object>();
for (Bean bean : beans) {
CreationalContext cc = bm.createCreationalContext(bean);
//Instantiates bean if not already in-service (undesirable)
Object beanInstance = bm.getReference(bean, bean.getBeanClass(), cc);
beanInstances.add(beanInstance);
}
return beanInstances;
If you are sure that there is only one bean of the specific type you can use beans.iterator.next().

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.

Categories