How to evaluate which page to show in PostConstruct? - jsf

Imagine this situation:
I have a SessionScoped bean (named TheSessionBean) that is a ManagedProperty of another bean (named AnotherBean).
#ManagedBean
#ViewScoped
public class AnotherBean implements Serializable {
#PostConstruct
public void init() {
//Evaluate here!
}
#ManagedProperty(value = "#{theSessionBean}")
private TheSessionBean theSessionBean;
//Getter and Setter...
}
I need to evaluate the value of the ManagedProperty (theSessionBean) in order to know if a page can be showed without the user interaction and before the page is shown.
As I understand this must be evaluated in the PostConstruct method (so I can get the value of the Session of the ManagedProperty).
TheSessionBean has only a String property named permission.
So first of all I need to know if:
theSessionBean.getPermission() == null in order to redirect to a page named one
theSessionBean.getPermission().equals("two") in order to redirect to a page named two
More evaluations...
The problem is that the PostConstruct method must be void and I need to redirect to the corresponding page.
How can I do that?

You can use ExternalContext.redirect in your PostConstruct method.
if (someCondition)) {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/one");
}

Best practice is to use JSF system events- PreRenderViewEvent PostConstructApplicationEvent PreDestroyApplicationEvent
JSF events

Related

How to pass bean property from one view to another view

I'm using JSF 2.1 and Primefaces:
I have a view scoped managed bean with a managed property and a method that set something on other view scoped managed bean and forward to other page referencing that managed bean:
#ManagedBean
#ViewScoped
public class HelloMB {
#ManagedProperty("otherMB")
private OtherMB other;
public String changeOtherMB() {
otherMB.setAnyObject(new Object());
return "otherPage.xhtml";
}
}
#ManagedBean
#ViewScoped
public class OtherMB {
private Object o;
public void setAnyObject(Object o) {
this.o = o;
}
}
So, when otherPage is rendered o is null.
You have idea how could I solve this? How can I retain an Object in a #ViewScoped managed bean and keep it live on other page without using #SessionScoped?
The view scope is destroyed and recreated once you navigate to a different JSF view. You know, the view scope lives as long as you're interacting with the same JSF view. In this particular case you effectively end up with two instances of the #{otherMB} managed bean during one request. One instance which is used by the source view and another instance which is used by the destination view.
As the second view is created within the very same request, you could just pass it as a request attribute.
#ManagedBean
#ViewScoped
public class HelloMB implements Serializable {
public String changeOtherMB() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.getRequestMap().put("anyObject", anyObject);
return "otherPage.xhtml";
}
}
#ManagedBean
#ViewScoped
public class OtherMB {
private Object anyObject;
#PostConstruct
public void init() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
this.anyObject = ec.getRequestMap().get("anyObject");
}
}
I however wonder if you're aware about the importance of idempotent vs non-idempotent requests. Perhaps you actually need a "plain vanilla" link without the need to invoke a view scoped bean action method. See the last "See also" link below for an extensive example on that.
See also:
How to choose the right bean scope?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Creating master-detail pages for entities, how to link them and which bean scope to choose

JSF Pass a map in ViewScoped Bean between two pages

I have two different pages. In the first page I have a Map in a ViewScoped Bean, and in the second page there is another ViewScoped Bean that needs the Map in the first page. How can I pass the Map between the two pages?
I've thought of transforming the Map into a JSON string, and passing through <f:viewParams>, but that might make the url too long.
Any ideas will be appreciated!
Given that the second page is been opened by a PRG request, your best bet is to make use of the flash scope. You can put flash scoped attributes in the map as available by ExternalContext#getFlash() and you can get them in the next request by the very same ExternalContext#getFlash() map (which is in EL scope also available by #{flash}).
So, e.g. this should do: in the action method of backing bean of first page:
public String submit() {
// ...
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.getFlash().put("data", data);
return "page2?faces-redirect=true";
}
And then a property of backing bean of second page (page2):
#ManagedProperty("#{flash.data}")
private Map<String, String> data; // Setter required.
Or, alternatively, the postconstruct of backing bean of second page:
private Map<String, String> data;
#PostConstruct
public void init() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
data = (Map<String, String>) ec.getFlash().get("data");
}

How do I force a managed bean to initialize first?

I have a navigation managed bean for each user.
and I need it to initialize first before any other bean because a value is required from the bean.
May I know how do I perform that?
I have tried eager="true" but it doesn't work.
any quick and easy solution via faceconfig would be greatly appreciated.
Just perform the desired initialization job in bean's #PostConstruct.
#PostConstruct
public void init() {
// Here.
}
It'll be invoked when the bean is injected/referenced from another bean for the first time.
The eager=true works only on application scoped beans.
From what I see you should reference the other bean. Let's assume a have a utility class that can pull a bean from the context.
Basically ->
//Bean A
public void doSomething()
{
String required = Utility.getBeanB().getRequiredValue();
use(required);
}
...
//Bean B
public String getRequiredValue()
{
return "Hi, I'm a required value";
}
I have several large web apps that have a "Session Bean" that stores stuff like user preferences, shared objects etc... and this method works perfectly. By using a reference to the bean you eliminate the need to chain the initialization. That method will always DEPEND on the method in the other bean, thus guaranteeing the order of initialization.
There's a variety of ways to access the bean but I usually go through the EL route ->
Get JSF managed bean by name in any Servlet related class
Best of luck, I try to stay "functionally pure" when I can--and I hope that get's a laugh considering the language!
Here's some cool hax for ya, in case other solutions aren't working for you due to various circumstances...
Let's say I have a class Alpha that I want initialized first:
public class Alpha {
#PostConstruct
public void init() {
}
}
I can put the following method in Alpha:
#ManagedBean(name = "Alpha", eager = true)
public class Alpha {
public static void requireAlpha() {
FacesContext context = FacesContext.getCurrentInstance();
Object alpha = context.getApplication().evaluateExpressionGet(context, "#{Alpha}", Object.class);
System.out.println("Alpha required: " + alpha.toString());
}
#PostConstruct
public void init() {
}
}
Then, in any classes that are initializing too early, simply call:
Alpha.requireAlpha();
// ...
// (Code that requires Alpha to be initialized first.)
And if there's a ChildAlpha class that extends Alpha that you really want to be initialized (rather than the parent), make sure to use "ChildAlpha" instead, in both the name="" and the EL Expression ("#{}").
See here for more infos: Get JSF managed bean by name in any Servlet related class

c:set for bean properties

I'm looking for some piece of code for setting a property in a JSF managed bean. My first idea was something like that:
<c:set var="#{loginBean.device}" value="mobil"></c:set>
That means I want to set the attribute device to the value "mobil" without a button have to been clicked.
Yes, you can use c:set for this purpose.
<c:set value="mobil" target="#{loginBean}" property="device" />
Doc: http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/pdldocs/facelets/c/set.html
However, setting a static value rarely makes sense. You might consider to set a default value directly in your managed bean class. Also in terms of maintainability since you can handle constants better in the Java code than in the view layer.
I think you want the JSF tag child tag setPropertyActionListener. You can set this as a child tag in any ActionComponent.
<h:anyActionComponent id="component1">
<f:setPropertyActionListener target="#{loginBean.device}" value="mobil" />
</h:anyActionComponent>
UPDATE:
I originally misunderstood the users problem. They have a page, and they want a property to be set when the page loads. There is a couple ways to do this, but both are a little different. If you want to set a property to a value after every postback then you can use the #PostConstruct annotation on a ManagedBean method.
#PostConstruct
public void initializeStuff() {
this.device = "mobil";
}
Now if I have a ViewScoped or SessionScope bean that needs to be initialized with a default value just once when the page loads then you can set a phase lifecycle event that will run after every postback and check to see if the page should be initialized or not.
mah.xhmtl:
<f:event listener="#{loginBean.initialize()}" type="preRenderView" />
LoginBean:
public void initialize() {
if (this.device == null)
this.device = "mobil";
}
I am not able to Comment: If you need the value to be ready on page on load, you could use Managed Bean to directly initialize value or use its constructor or #PostConstruct to do the same.
#ManagedBean
#ResquestScoped
public class LoginBean {
private String device = "some value";
//Using Constructor
public LoginBean() {
device = getvalueFromSomewhere();
}
//Using PostConstruct
#PostConstruct
public void init() {
device = getvalueFromSomewhere();
}
}
Instead of setting the value in the xhtml file you can set via another ManagedBean. For instance if you have managedBean1 which manages page1.xhtml and managedBean2 which manages page2.xhtml. If page1.xhtml includes page2.xhtml like:
<ui:include src="page2.xhtml"/>
in managedBean1 you can have at the top
#ManagedProperty(value = "#{managedBean2}")
private ManagedBean2 managedBean2;
and in the PostConstruct
#PostConstruct
public void construct() {
managedBean2.setProperty(...);
}
worked for me anyway...

NullpointerException Binding not working JSF managed bean

I created a simple HtmlInputText
<h:inputText binding="#{IndexBean.objUIInput}" />
Then in my managed bean, it is :-
private UIInput objUIInput;
public UIInput getObjUIInput() {
objUIInput.setValue("laala");
return objUIInput;
}
public void setObjUIInput(UIInput objUIInput) {
System.out.println("Set!!");
this.objUIInput = objUIInput;
}
But i always get NullpointerException. Do i need to do anything extra on my JSF page? like we do jsp:usebean setproperty? Please help me.
Whenever you'd like to change the component's default state/behaviour prior to display, then you need to instantiate it yourself. I.e. during declaration:
private UIInput objUIInput = new HtmlInputText();
or during construction:
public Bean() {
this.objUIInput = new HtmlInputText();
}
or, as Bozho suggested, using #PostConstruct:
#PostConstruct
public void init() {
this.objUIInput = new HtmlInputText();
}
(which will take place after construction of the bean and initialization/setting of all managed properties).
And indeed, you should preferably not do any business logic in getters/setters. They are to be used to access bean properties and they can be called more than once during bean's life.
As per the comments, you can alternatively also move the UIInput#setValue() call to the setter method. JSF will call it once directly after precreating the component.
public void setObjUIInput(UIInput objUIInput) {
this.objUIInput = objUIInput;
this.objUIInput.setValue("laala");
}
When you bind a component, the getter and setter are supposed to be simple - only get/set - no logic inside them.
Perhaps the JSF lifecycle is calling the getter to check whether it needs to instantiate the component, and the getter initially would throw a NPE.
Remove all logic from your getter, or at least add a null check.
Actually, I'd advice for not using binding at all.
If you want to set an initial value to your component, use a method annotated with #PostConstruct and assign the value there, then use the value attribute.

Resources