Session Bean Data is lost after page reload or page change - jsf

I'm working on a JSF Project using a Wildfly 8 Server and jsf 2.2.
I've a web part with xhtml and beans + ejb part with models etc and a mysql database.
Part of Model (EJB part): Foo.java
String name = "";
Object Foo2 = new Foo2();
Part of Model (EJB part): Foo2.java
private static final long serialVersionUID = 1L;
String name = "";
Now I've input like this: input.xhtml
<f:metadata>
<f:event listener="#{ InputBean.init() }" type="preRenderView" />
</f:metadata>
<h:inputText
value="#{ InputBean.actualFoo.name }">
</h:inputText>
<h:selectOneMenu
value="#{InputBean.currentSelectedFoo2_ID}">
<f:selectItems value="#{InputBean.lhm_AllFoo2}" />
</h:selectOneMenu>
and a bean: InputBean.java
#SessionScoped
#ManagedBean(name = "InputBean")
public class InputBean implements Serializable
private static final long serialVersionUID = 1L;
private Long currentSelectedFoo2_ID;
private LinkedHashMap<String, Object> lhm_AllFoo2;
private Foo actualFoo;
public InputBean() {
lhm_AllPermissions = new LinkedHashMap<String, Object>();
actualFoo = new Foo();
}
public void init()
// Method of interface in EJB part which gives me all Foo2 to a list
List<Foo2> list_AllFoo2 = foo2Interface.getAllFoo2;
if ((list_AllFoo2 != null) && (list_AllFoo2.size() > 0)) {
for (Foo2 foo2 : list_AllBFoo2) {
lhm_AllFoo2.put(foo2.getName(), foo2.getId());
}
}
When I input data in the inputField and select data the selectonemenu and then reload the page (f5) or change to another page (of the same project) and go back the data in the input field is still avaiable but the selectonemenu is reseted to the default value.
I tried to debug the problem, but the data is already lost when the init is accessed, no setter of the bean is called before. The constructer isn't called too, so everything seems to be correct. The bean data which isn't linked to an input isn't lost too.
Is this a normal JSF problem and is there a way to solve that?

Related

Clear SessionScoped bean when refreshing page

I am using a Bean (MenuBean) to dynamically create a
<p:breadCrumb model="#{menuBean.model}" />
When transitioning through each page of my application, I push or pop pages from a "page stack", so as to adapt the breadCrumb of each page.
#ManagedBean
#SessionScoped
public class MenuBean implements Serializable {
private MenuModel model;
private int navIdx;
private ArrayList<String[]> pageStack;
#PostConstruct
public void init() {
pageStack = new ArrayList<>();
navIdx = 0;
String [] home = new String[2];
home[0] = "Home";
home[1] = "home.xhtml";
pageStack.add(home);
refreshModel();
}
private void refreshModel() {
model = new DefaultMenuModel();
int i = 0;
for(String[] s: pageStack) {
DefaultMenuItem index = new DefaultMenuItem();
index.setValue(s[0]);
index.setCommand("#{menuBean.navigate}");
index.setParam("index", String.valueOf(i++));
model.addElement(index);
}
}
private void push(String [] page) {
pageStack.add(page);
navIdx++;
refreshModel();
}
private String pop() {
pageStack.remove(navIdx--);
String[] prevPage = pageStack.get(navIdx);
refreshModel();
return prevPage[1];
}
}
In order to maintain this stack, my MenuBean is SessionScoped.
However, when I refresh the last page for example, the initial page is shown (since the url does not change) but the breadCrumb still displays the whole stack.
My question is: Is there a way to clear the MenuBean when the user leaves the page, or refreshes it?
One way you could refresh the bean is using remoteCommand with set auto run on true. So once you refresh the page remote commad will fire and call method in backing bean.
<!-- init bean on page load -->
<h:form id="initializePageDataForm">
<p:remoteCommand name="initializePageDataCommand" autoRun="true" action="#{MenuBean.init()}" />
</h:form>
This worked for me using JSF instead of Primefaces.
<!-- init bean on page load -->
<f:metadata>
<f:event type="preRenderView" listener="#{MenuBean.init() }" />
</f:metadata>

Best solution to pass objects between two ViewScoped ManagedBeans

I'm wondering what the best practices are to pass data (an object) between two ViewScoped beans.
They need to be view scoped because of the problem that's brilliantly explained here (to put it short: In both views I'm using a h:commandLink from within a h:dataTable which requires the data model to still be present when submitting).
My problem now is that clicking the link also navigates to a new view, so using the following code, my object gets passed but the DetailViewController instance gets killed right after that and a new one is created when the view changes (as you would expect).
View:
<h:dataTable value="#{searchController.dataModel}" var="item">
...
<h:column>
<f:facet name="header">Action</f:facet>
<h:commandLink id="open" value="open" action="#{searchController.showDetail(item)}" />
</h:column>
</h:dataTable>
Bean:
#ManagedBean
#ViewScoped
public class SearchController {
#ManagedProperty(value="#{detailViewController}")
private DetailViewController detailViewController;
// getters, setters, etc. ...
public String showDetail(Item i) {
detailViewController.setItem(i);
return "view_detail.xhtml";
}
}
How would you solve this? I thought about putting the object inside Flash: FacesContext.getExternalContext.getFlash()... Is there an easier or more elegant solution?
You can use view parameters. (See How do you pass view parameters when navigating from an action in JSF2?)
Typically, your method return the url with query parameters:
public String showDetail(Item i) {
return "view_detail.xhtml?id="+i.getId();
}
And in your view_detail.xhtml file, you add a f:viewParam tag evaluating to on of your bean field:
<f:metadata>
<f:viewParam name="id" value="#{myBean.id}" />
</f:metadata>
Then from your backing bean, you use that field to get your Item instance in your #postConstruct method.
If you don't use the f:viewparam tag, you can also fetch the request parameters to obtain the id.
private String id;
private Item item;
#PostConstruct
public void init() {
if (id != null) {
item = fetchItem(id);
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();
if (requestParameters.containsKey("id")) {
id = requestParameters.get("id");
item = fetchItem(id);
} else {
throw new WebServiceException("No item id in request parameters");
}
}
}

Using h:selectBooleanCheckbox with c:if to obtain row value of a <rich:datatable> - JSF

I'm using a <rich:datatable> to show the content of a List<Map<String, String>
In the code below, spotlightPtBindings is the List<Map<String, String> and spotlightbinding represents each Map<String, String>. In the first column, I'm showing one selectBooleanCheckBox for eah row. When a selectBooleanCheckBox is checked, I'd like to send the value of the Map<String, String> corresponding to the key "URI" as a parameter to the method: inserirBean.onSelectedCheckBox(uri), and that's why I put this value in a ui:param of name: uri. The problem here is that when I try to print the value uri received in inserirBean.onSelectedCheckBox(uri), I don't get the any output, as if it is empty. Below there's the rest of the code:
InsereDocumento.xhtml
<rich:dataTable value="#{inserirBean.spotlightPtBindings}" var="spotlightbinding">
<rich:column>
<f:facet name="header">*</f:facet>
<ui:param name="uri" value="#{spotlightbinding['URI']}"/>
<h:selectBooleanCheckbox value="#{selectionBean.selected}" />
<c:if test="#{selectionBean.selected}">
#{inserirBean.onSelectedCheckBox(uri)}"
</c:if>
</rich:column>
<c:forEach items="#{inserirBean.variableNamesPt}" var="vname">
<rich:column>
<f:facet name="header">#{vname}</f:facet>
#{spotlightbinding[vname]}
</rich:column>
</c:forEach>
</rich:dataTable> <br />
SelectionBean
package managedBeans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
#ManagedBean
public class CheckBoxSelectionBean implements Serializable {
private transient boolean selected = false;
private static final long serialVersionUID = 1L;
public CheckBoxSelectionBean() {
// TODO Auto-generated constructor stub
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
InserirBean - I'm not showing here how the List<Map<String, String>> named spotlightPtBinding and how the List<String> variableNamesPt were populated, because it was a complex process, but I can tell you they are certainly populated, cause I can see their content on the screen.
#ManagedBean
public class InsereDocumentoBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> variableNamesPt = new ArrayList<String>();
private List<Map<String, String>> spotlightPtBindings = new ArrayList<Map<String, String>>();
public List<String> getVariableNamesPt() {
return variableNamesPt;
}
public List<Map<String, String>> getSpotlightPtBindings() {
return this.spotlightPtBindings;
}
public void onSelectedCheckBox(String uri) {
System.out.println("URI: " + uri);
}
}
What may the problem be? Thank you! I'm new to JSF and need your help!
In JSF rendering is a two-step process: there's view build time and view render time.
Although they're in the same file, some tags take effect at view build time, some at render time.
JSTL tags like <c:forEach>, <c:if> and all tag handlers (including <ui:param>, see here) are evaluated at view build time, they add content to the "final" xml tree that is then rendered by JSF.
JSF HTML tags and derivates like <rich:dataTable> are evaluated at view render time, so the datatable's var is evaluated later then the <ui:param> which causes spotlightbinding not to be bound when it's assigned to uri.
Instead, I suggest you assign an ajax listener to call the function:
<h:selectBooleanCheckbox value="#{selectionBean.selected}">
<f:ajax listener="#{inserirBean.onSelectedCheckBox(spotlightbinding['URI'])}" />
</h:selectBooleanCheckbox>
Note that the listener is called whenever the value changes.

java.lang.NullPointerException at org.primefaces.extensions.component.remotecommand.RemoteCommandRenderer.decode

On the Facelet, I try to use <pe:remoteCommand> to update backingbean value:
<pe:remoteCommand name="saveMapArea" process="#this" actionListener="#{defineMapArea.createMapArea}">
<pe:assignableParam name="areaString" assignTo="#{defineMapArea.tagMapArea.mapArea}"/>
<pe:assignableParam name="areaName" assignTo="#{defineMapArea.tagMapArea.name}" />
<pe:assignableParam name="castId" assingTo="#{defineMapArea.tagMapArea.castId}" />
</pe:remoteCommand>
castId value is retrieved from a dropdown list by jQuery when user clicks submit button, the code for dropdown list is:
<h:selectOneMenu id="area_assign_device">
<f:selectItem itemLabel="Select Icast" itemValue="" />
<f:selectItems value="#{defineMapArea.castList}" var="cast" itemLabel="#{cast.name}" itemValue="#{cast.castId}"/>
</h:selectOneMenu>
the code for submit button is:
<p:commandButton value="Submit" type="button" onclick="CreateArea.saveArea()"/>
the code for calling remotecommand 'saveMapArea' is:
saveArea : function() {
if(CreateArea.validate()) {
// ...some other code to init map area...
var name=jQuery('#area_name_text').val();
var castId=jQuery('#area_assign_device').val();
saveMapArea(mapArea, name, castId);
CreateArea.points = [];
}
}
and my backing bean is:
#ManagedBean
#RequestScoped
public class DefineMapArea extends BaseJsfBean {
private static final long serialVersionUID = 1L;
private static Log log = LogFactory.getLog(DefineMapArea.class);
private TagMapArea tagMapArea;
private List<TagMapArea> areaList;
private String areaListJson;
#ManagedProperty(value="#{tagCustomService}")
private ITagCustomService tagCustomService;
#Override
protected void init() throws Exception {
// ..some initializations...
}
public void createMapArea() {
log.info("Area Persisting : " + tagMapArea.getMapArea());
tagMapArea.setTagMapImageId(2);
tagMapArea.setMapAreaType("test");
tagMapArea.setDescription("test");
}
// ....all the getters and setters....
}
TagMapArea is the JPA entity, the part including castId field is:
#Column(name = "cast_id", nullable = false)
protected Integer castId;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="cast_id", nullable=false, insertable=false, updatable=false)
protected TagCast cast;
The problem is when I click submit button, it throws a NullPointerException like this:
java.lang.NullPointerException
at org.primefaces.extensions.component.remotecommand.RemoteCommandRenderer.decode(RemoteCommandRenderer.java:82)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1377)
at org.apache.myfaces.context.servlet.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:731)
at org.apache.myfaces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:214)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:932)
I'm pretty sure this is caused by castId field in the remote command, because if I remove that field, it works ok. I am confused why the selected value retrieved from the dropdown list doesn't get sent to the remotecommand. Does anyone konw where the problem is?
Still not sure where went wrong ,but i found a walk around, instead of using remote command in primefaces extentions, I tried the original remote command in primefaces and it works.
The code after change is:
<p:remoteCommand name="saveMapArea" actionListener="#{defineMapArea.createMapArea}" />
and for the javascript part, it becomes:
saveMapArea([{name:'mapArea', value:mapArea},{name:'name',value:name},{name:'castId',value:castId}]);
in the backing bean's createMapArea method, the code snippet to get values is:
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
String mapArea = (String)map.get("mapArea");
String name = (String)map.get("name");
String castId = (String)map.get("castId");
log.info("Area Persisting : " + mapArea);
log.info("name: " + name + " castId: " + castId);

JSF #ManagedProperty doesn't work

On various places they said that you should use #ManagedProperty to get a request parameters. The problem is that I try to get the token from the request string but it somehow stays null all the time.
The link where the page is with called looks like this:
http://example.com/faces/Check.xhtml?token=EC-8AT450931P272300C&ID=VKEFF29XNGNJG
The bean:
#Named(value = "bean")
#RequestScoped
public class Bean implements Serializable {
#Inject
private AccountBean account;
#Inject
private Service web;
#ManagedProperty(value = "#{param.token}")
private String token;
#ManagedProperty(value = "#{param.ID}")
private String id;
#PostConstruct
public void init() {
System.out.println("token: " + token);
}
The page
<ui:define name="content">
<h:form>
<pou:commandButton action="#{bean.test()}" value="complete"/>
</h:form>
</ui:define>
And other things I tried:
Map<String, String> e = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
This doesn't contain the request parameters also. Same goes for all the facesContext things where you can get requests with.
Help will be appreciated.
P.S. I can't change anything behind the ? cause its called from a program not in my reach
Okay made it work.
#Inject to pass params to a CDI #Named bean via URL
This was the solution just needed to add a few more things to my site
<ui:define name="content">
<h:form>
<h:inputHidden value="#{bean.token}"/>
<h:inputHidden value="#{bean.id}"/>
<pou:commandButton action="#{bean.test()}" value="complete"/>
</h:form>
</ui:define>
And remove the #{param.xxx} part from the naming
#Inject #HttpParam
private String token;
#Inject #HttpParam(value = "ID")
private String id;

Resources