I've made small jsf app and a bit confused about lifecycle order, i'm getting unexpected NPE on postback even though i'm creating that object on every request. Can someone explain what's happening under the covers. Here is the code:
Entity.java
public class Entity {
private Long id;
private String property;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}
Bean.java
import javax.enterprise.inject.Model;
#Model
public class Bean {
private Long id;
private Entity entity;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Entity getEntity() {
return entity;
}
public void loadEntity() {
this.entity = new Entity();
}
}
edit.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:o="http://omnifaces.org/ui">
<f:view transient="true">
<f:metadata>
<f:viewParam name="id" value="#{bean.id}"/>
<f:viewAction onPostback="true" action="#{bean.loadEntity()}"/>
</f:metadata>
<h:body>
<o:form useRequestURI="true">
<h:inputText value="#{bean.entity.property}"/>
<h:commandButton value="Save"/>
</o:form>
</h:body>
</f:view>
</html>
Action methods like <f:viewAction action> are invoked during invoke application phase. The model values are updated during update model values phase. So, the entity is created one phase too late and still null when property needs to be set.
Get rid of the <f:viewAction> and make it a #PostConstruct method instead.
#PostConstruct
public void init() {
this.entity = new Entity();
}
Related
In a website we want to integrate some snippets provided by jsf-applications, think of a dashboard-app or a "portal-light". While analyzing the requirements we came across a blog-post by Arjan Tjims on jsf 2.3 new features, where he mentioned a new "namespaced mode":
In namespaced mode, which is specifically intended for Portlets but can be used in other environments as well, the partial response is given an id that's taken to be the "naming container id". All predefined postback parameter names (such as "javax.faces.ViewState", "javax.faces.ClientWindow", "javax.faces.RenderKitId", etc) are prefixed with this and the naming separator (default ":"). e.g. javax.faces.ViewState" becomes "myname:javax.faces.ViewState". Namespaced mode is activated when the UIViewRoot instance implements the NamingContainer interface.
Our application might be a usecase for that "namespaced mode", so we want to give it a try.
We built a MyUIViewRoot where we implemented NamingContainer and wrapped the original UIViewRoot-instance. We registered a MyViewHandler in faces-config.xml which handles the wrapping of the ViewRoot. For testing we used a simple counter-app with two <h:form>-elements (seems to be important).
We find that "namespace mode" seems to be activated, eg the javax.faces.ViewState indeed is prepended by some namespace and becomes j_id1:javax.faces.ViewState:0. But both actions do not work any more - the postback request does not restore the View any more but creates a new one. So with our simple approach we are missing something (btw, removing only the implements NamingContainer from MyUIViewRoot the counter-app works fine again).
Is there some documentation, a howto or a working example out there that we have overlooked?
How to activate "namespace mode" correctly? What have we missed to make the postback work again?
How can we make MyUIViewRoot to prepend the ViewState with myNamespace?
The application is running in a payara-5 application server.
Our index.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head/>
<h:body>
<h:form id="counterForm">
<h:panelGrid columns="2">
<h:outputLabel value="Counter" />
<h:outputText value="#{counterUiController.counter}" />
</h:panelGrid>
<h:commandButton value="inc" action="#{counterUiController.incAction}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
<h:form id="resetForm">
<h:commandButton value="reset" action="#{counterUiController.resetAction}">
<f:ajax execute="#form" render=":counterForm" />
</h:commandButton>
</h:form>
</h:body>
</html>
The CounterUiController:
#Named
#ViewScoped
public class CounterUiController implements Serializable {
private int counter;
public int getCounter() {
return counter;
}
public void incAction() {
counter++;
}
public void resetAction() {
counter=0;
}
}
Our UIViewRoot-Implementation:
public class MyUIViewRoot extends UIViewRoot implements NamingContainer, FacesWrapper<UIViewRoot> {
private static final Logger LOG = Logger.getLogger(MyUIViewRoot.class.getName());
private UIViewRoot wrapped;
public MyUIViewRoot(UIViewRoot wrapped) {
this.wrapped = wrapped;
LOG.log(Level.INFO, "new instance created: {0}", this);
}
#Override
public UIViewRoot getWrapped() {
return wrapped;
}
#Override
public String createUniqueId() {
return wrapped==null ? null : wrapped.createUniqueId();
}
#Override
public void setId(String id) {
if( wrapped!=null ) {
wrapped.setId(id);
}
}
// all other methodes delegated to `wrapped` directly
}
Our ViewHandler:
public class MyViewHandler extends ViewHandlerWrapper {
private static final Logger LOG = Logger.getLogger(MyViewHandler.class.getName());
public MyViewHandler(ViewHandler wrapped) {
super(wrapped);
}
#Override
public UIViewRoot createView(FacesContext context, String viewId) {
UIViewRoot retval = super.createView(context, viewId);
retval = wrapIfNeeded(retval);
LOG.log(Level.INFO, "view created: {0}", retval);
return retval;
}
#Override
public UIViewRoot restoreView(FacesContext context, String viewId) {
UIViewRoot retval = super.restoreView(context, viewId);
retval = wrapIfNeeded(retval);
LOG.log(Level.INFO, "view restored: {0}", retval);
return retval;
}
private UIViewRoot wrapIfNeeded(UIViewRoot root) {
if (root != null && !(root instanceof MyUIViewRoot)) {
LOG.log(Level.INFO, "view wrapped: {0}, {1}", new Object[] { root, root.getId() });
return new MyUIViewRoot(root);
} else {
return root;
}
}
}
You need to replace the UIViewRoot not to wrap it.
public class NamespacedView extends UIViewRoot implements NamingContainer {
//
}
And then in faces-config.xml.
<component>
<component-type>javax.faces.ViewRoot</component-type>
<component-class>com.example.NamespacedView</component-class>
</component>
That's basically all. See also the Mojarra IT on this.
I have a problem using autocomplete primefaces component inside of an UIInput composite. My goal is to init the application with preselected value in autocomplete field, showing a label accordingly. Below I show a test code
Page testPage.xhtml
<f:view id="view" locale="#{webSession.currentLanguage.locale}">
<h:head>
<title>...</title>
</h:head>
<h:body>
<h:form>
<utils:element/>
<p:autoComplete
value="#{testPage.attr}"
completeMethod="#{testPage.completeMethod}"
var="item"
itemLabel="#{item}"
itemValue="#{item}" />
</h:form>
</h:body>
</f:view>
Managed Bean TestPage.xhtml
#ManagedBean(name = "testPage")
#ViewScoped
public class TestPage {
private String attr;
#PostConstruct
public void init(){
attr = "value 1";
}
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
this.attr = attr;
}
public List<String> completeMethod(String query) {
return Arrays.asList(new String[]{"1111", "2222", "3333"});
}
}
This approach works fine using the autocomplete directly on testPage.xhtml. However, I want to wrap this autocomplete in a element composite, as showed in following code
element.xhtml composite page
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="elementComponent">
</cc:interface>
<cc:implementation>
<p:autoComplete
value="#{cc.attr}"
completeMethod="#{cc.completeMethod}"
var="item"
itemLabel="#{item}"
itemValue="#{item}" />
</cc:implementation>
</ui:component>
ElementComponent composite backing
#FacesComponent("elementComponent")
#ViewScoped
public class ElementComponent extends UIInput implements NamingContainer{
private String attr;
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
public List<String> completeMethod(String query) {
return Arrays.asList(new String[]{"value 1", "value 2", "value 3"});
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
attr = "value 1";
}
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
this.attr = attr;
}
}
But when I include the element composite in testPage.xhtml, the autocomplete does not show the preselected value (unlike the direct implementation). Is there any way to solve this? Maybe any method or attribute is missing in the implementation of FacesComponent? I tend to think this is a bug between the implementation of primefaces and the implementation of composite, but I am not sure.
The problem was the method encodeBegin(). This implementation require the encode of the component class, and the encode of the parent (UIInput).
Incorrect
#Override
public void encodeBegin(FacesContext context) throws IOException {
attr = "value 1";
}
Correct
#Override
public void encodeBegin(FacesContext context) throws IOException {
attr = "value 1";
super.encodeBegin();
}
Im trying to create a JSF page that lets the user select X amount of ingredients, and then saves those selected ingredients to a list.
Ingredient is an object with two values, String IngredientName and int ingredientPrice.
What I want to do is to create 1 selectItem per Ingredient in an IngredientList (dynamically sized), and then save the selected items to another list of ingredients.
I've tried doing this multiple different ways but either I get classcast exceptions or the checkboxes don't appear at all.
My Bean:
#ManagedBean
#SessionScoped
public class ManagedIngredientsBean {
#EJB
IngredientBean iBean;
private List<Ingredient> ingredientList;
private List<Ingredient> checkedOptions;
private List<SelectItem> selectList;
public ManagedIngredientsBean() {
}
public String createNew(){
ingredientList = iBean.getAllIngredients();
selectList = new ArrayList<SelectItem>(ingredientList.size());
for(Ingredient i : ingredientList){
selectList.add(new SelectItem(i.getIngredientName()));
}
return "createnew.xhtml";
}
public List<SelectItem> getSelectList() {
return selectList;
}
public void setSelectList(List<SelectItem> selectList) {
this.selectList = selectList;
}
public List<Ingredient> getCheckedOptions() {
return checkedOptions;
}
public void setCheckedOptions(List<Ingredient> checkedOptions) {
this.checkedOptions = checkedOptions;
}
public List<Ingredient> getIngredientList() {
return ingredientList;
}
public void setIngredientList(List<Ingredient> ingredientList) {
this.ingredientList = ingredientList;
}
#FacesConverter(value="userConverter")
public static class UserConverter implements Converter {
public Object getAsObject(FacesContext facesContext,
UIComponent component, String value) {
return value;
}
public String getAsString(FacesContext facesContext,
UIComponent component, Object o) {
Ingredient i = (Ingredient) o;
return i.getIngredientName();
}
}
}
IngredientBean used to get the Ingredient items from the persistence database and returning them as a list:
#Stateless(name = "IngredientEJB")
public class IngredientBean {
EntityManagerFactory entFactory;
EntityManager em;
public IngredientBean() {
entFactory = Persistence.createEntityManagerFactory("NewPersistenceUnit");
em = entFactory.createEntityManager();
}
public List<Ingredient> getAllIngredients(){
TypedQuery<Ingredient> ingQuery = em.createQuery("SELECT i FROM Ingredient i", Ingredient.class);
List<Ingredient> iList = ingQuery.getResultList();
return iList;
}
}
My JSF Page:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Create New Order</title>
</h:head>
<h:body>
<h:form>
<h:selectManyCheckbox value = "#{managedIngredientsBean.checkedOptions}">
<f:converter converterId="userConverter"/>
<f:selectItem value = "#{managedIngredientsBean.selectList}" var = "item" itemLabel = "#{item.getIngredientName()}" itemValue = "#{item}"/>
</h:selectManyCheckbox>
</h:form>
</h:body>
</html>
I'm probably missing something obvious or simply misunderstanding how to use the selectManyCheckbox element but I'm completely stuck on how to fix this. Appreciate any answers on how I should be implementing this. :)
Edit: Forgot to mention, the createNew() method in the managed bean is called in the previous JSF page and redirects to this one.
your converter is broken.
first, it have to be a bean so must not be a static class.
second, it "should" be symmetric:
x.equals(c.getAsObject(ctx, comp, c.getAsString(ctx, component, x))); "should" be true.
#FacesConverter(value="userConverter")
public class UserConverter implements Converter
{
public Object getAsObject(FacesContext facesContext, UIComponent component, String value)
{
return database.loadIngredientByUniqueValue(value);
}
public String getAsString(FacesContext facesContext,UIComponent component, Object o)
{
Ingredient i = (Ingredient) o;
return i.getSomeUniqueValue();
}
}
i am using jsf 2.1.1 and primefaces 3.0.M4. i have a sample jsf page that used to post country comments. i use f:viewparam tag with converter to view country pages. here are the codes:
country.xhtml:
<f:metadata>
<f:viewParam name="country" value="#{countryBean2.selectedCountry}" converter="countryConverter" required="true"/>
</f:metadata>
<h:head>
<title>Country</title>
</h:head>
<h:body>
<h:form id="form">
<h:outputText value="#{countryBean2.selectedCountry.countryName}" />
<br/><br/>
<h:outputText value="Comment:" />
<h:inputText value="#{countryBean2.comment}" />
<br/>
<p:commandButton value="Send" action="#{countryBean2.sendComment}" update="#this" />
</h:form>
</h:body>
CountryBean2.java:
#Named("countryBean2")
#SessionScoped
public class CountryBean2 implements Serializable {
private EntityCountry selectedCountry;
private String comment;
public EntityCountry getSelectedCountry() { return selectedCountry; }
public void setSelectedCountry(EntityCountry newValue) { selectedCountry = newValue; }
public String getComment() { return comment; }
public void setComment(String newValue) { comment = newValue; }
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
public void sendComment() {
EntityManager em = emf.createEntityManager();
try {
FacesMessage msg = null;
EntityTransaction entr = em.getTransaction();
boolean committed = false;
entr.begin();
try {
EntityCountryComment c = new EntityCountryComment();
c.setCountry(selectedCountry);
c.setComment(comment);
em.persist(c);
committed = true;
msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_INFO);
msg.setSummary("Comment was sended");
} finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
}
}
CountryConverter.java:
public class CountryConverter implements Converter {
public static EntityCountry country = new EntityCountry();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
#Override
public EntityCountry getAsObject(FacesContext context, UIComponent component, String value) {
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT c FROM EntityCountry c WHERE c.countryName = :countryName")
.setParameter("countryName", value);
country = (EntityCountry) query.getSingleResult();
return country;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
EntityCountry c = (EntityCountry) value;
return c.getCountryName();
}
}
i want to call "setComment" setter without calling CountryConverter, when i am using commandbutton to post comment. how can i do that ?
Unfortunately, that's by design of the <f:viewParam> component. It will convert the request parameter and set the property on every HTTP request, also on postbacks. In order to change this behaviour, you would need to extend <f:viewParam> with a custom component which doesn't remember the initial request parameter in its state. It's relatiely simple, instead of delegating the setSubmittedValue() and getSubmittedValue() to StateHelper, you just need to make it an instance variable. This is described in detail in this blog.
#FacesComponent("com.my.UIStatelessViewParameter")
public class UIStatelessViewParameter extends UIViewParameter {
private String submittedValue;
#Override
public void setSubmittedValue(Object submittedValue) {
this.submittedValue = (String) submittedValue;
}
#Override
public String getSubmittedValue() {
return submittedValue;
}
}
OmniFaces has an ready-to-use component for this in flavor of <o:viewParam>. Here is the live example.
I am getting the null Converter error for what I thought was a very simple scenario:
<!-- My View -->
<ui:composition template="/template/template_v1.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<!-- Simplified for clarity -->
<h:form>
<div class="block-panel customer-data">
<h:outputLabel for="txtUsername">Username:</h:outputLabel>
<h:inputText id="txtUsername" name="Username"
value="#{userBean.user.id}"
styleClass="text" />
<rich:message id="errorUsername" for="txtUsername"/>
</div>
<!-- Other fields omitted for clarity -->
</h:form>
/* The User Bean - simplified */
#ManagedBean
#ViewScoped
public class UserBean implements Serializable {
private User user;
public User getUser() {
// Contains logic for reading a user from the database or creating a new
// user object
return user;
}
public void setUser(User user) {
this.user = user;
}
}
/* The user Entity - Simplified */
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "user_type", discriminatorType = DiscriminatorType.STRING)
public class User implements IEntity<String>, Serializable {
private static final long serialVersionUID = 1L;
private String id;
#Id
#Column(name = "username", length = 50)
#NotNull(message = "{userIdMandatory}")
#Size(max = 50)
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
}
/* The IEntity interface */
public interface IEntity<ID extends Serializable> {
ID getId();
void setId(final ID pId);
}
So essentially I'm trying to bind a string property of my user entity to a inputText field. As far as I'm concerned there should be no need for a conversion so I shouldn't be getting the error I'm seeing.
Interestingly, if I add the following getter and setter to my entity:
public String getTmpId() {
return this.id;
}
public void setTmpId(String id) {
this.id = id;
}
And then make the necessary changes to my view to bind to tmpId rather than id, everything works as expected.
This seems like a bug to me either to do with the fact that I am binding to a getter/setter defined in an interface, defined in a generic interface or because the getter is marked with the Id attribute. I would appreciate someone else's ideas however.
As an aside, I have inherited this design and don't particularly like it so I may just end up refactoring it to introduce a new username property rather than trying to use the Id.
To the best of my knowledge I believe this is caused by an obscure bug in BeanELResolver which is used to get the type of the property being bound to - rather than returning String it is returning Serializable, for which there is no converter and hence the error I am seeing.
It's not particularly elegant, but I have worked around this by adding a userId property to my userBean and then binding to that in my view instead of the Id property on the user entity. I then use that value to set the Id manually on the entity when I save it:
<!-- My New View -->
<ui:composition template="/template/template_v1.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<!-- Simplified for clarity -->
<h:form>
<div class="block-panel customer-data">
<h:outputLabel for="txtUsername">Username:</h:outputLabel>
<h:inputText id="txtUsername" name="Username"
value="#{userBean.userId}"
styleClass="text" />
<rich:message id="errorUsername" for="txtUsername"/>
</div>
<!-- Other fields omitted for clarity -->
/* The New User Bean - simplified */
#ManagedBean
#ViewScoped
public class UserBean implements Serializable {
private string userId;
private User user;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public User getUser() {
// Contains logic for reading a user from the database or creating a new
// user object
return user;
}
public void setUser(User user) {
this.user = user;
}
public void saveUser() {
if (user.getId() == null) {
user.setId(userId);
}
// Actual saving omitted for brevity
}
}