JSF use of ui:repeat varStatus.index as an array index - jsf

This code works in Jakarta Faces 2.3.14, but fails in 2.3.15 and 2.3.16:
<f:metadata>
<f:viewParam name="fid" value="#{myForm}" converter="#{formsConverter}" />
<f:viewAction action="#{myForm.init}" />
</f:metadata>
...
<ui:repeat var="q" value="#{myForm.questions}" varStatus="stat">
<tr><td>#{stat.index+1}.</td>
<td><h:outputText value="#{q}" /></td>
<td><h:selectOneRadio group="q#{stat.index}" value="#{myForm.answers[stat.index]}"
required="true" label="Question #{stat.index}" >
<f:selectItem itemValue="1" />
...
The part that fails is value="#{myForm.answers[stat.index]}". When I try to submit the form in Jakarta Faces 2.3.15, it throws the following exception:
org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [Faces Servlet] in context with path [] threw exception [/forms/myform.xhtml #43,117 value="#{myForm.answers[stat.index]}": Target Unreachable, [null] returned null] with root cause
javax.el.PropertyNotFoundException: Target Unreachable, [null] returned null
at org.apache.el.parser.AstValue.getTarget(AstValue.java:119)
at org.apache.el.parser.AstValue.getType(AstValue.java:58)
at org.apache.el.ValueExpressionImpl.getType(ValueExpressionImpl.java:174)
...
I've tried initializing answers in both #PostConstruct and also a viewAction, but still get the same error. If I access answers using a hard-coded number, e.g. answers[0], there is no error. The error only occurs with answers[stat.index]
I'm wondering if this is a regression or if the spec doesn't allow the use of varStatus.index as an array index, in which case I need to find a new way of doing it.
Bean code:
#Named #ViewScoped
public class MyForm {
protected String[] answers = new String[42];
#PostConstruct
public void init() {
answers = new String[42];
Arrays.fill(answers, "");
}
...
}
Update
I worked around this by using <c:forEach /> instead of <ui:repeat />, but it still seems like a bug given that <ui:repeat /> works in 2.3.14.

Related

UIInput set methods not called on submitting JSF Page with <f:viewParams>

I have a simple Form in my JSF page that looks as follows:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<f:view>
<h:head>
<f:metadata>
<f:viewParam name="cities" value="#{myBean.cities}" />
</f:metadata>
</h:head>
<h:body>
<h:form>
<h:messages id="messages" />
<h:selectManyCheckbox value="#{myBean.cities}" label="Select City" >
<f:selectItems value="#{myBean.allCities}" />
</p:selectManyCheckbox>
<h:commandButton value="Submit">
<f:ajax execute="#form" render="output"/>
</h:commandButton>
</h:form>
<h:panelGroup id="output">
Number of Selected Cities: #{myBean.cities.size()}
</h:panelGroup>
</h:body>
</f:view>
</html>
The matching backing bean:
With following bean methods:
#Named
#RequestScoped
public class MyBean {
private List<String> cities = new ArrayList<>();
public List<String> getCities() {
return cities;
}
public void setCities(List<String> cities) {
this.cities = cities;
}
public List<String> getAllCities() {
return new ArrayList<>(Arrays.asList(new String [] {
"Los Angeles",
"St. Louis",
"San Francisco",
"Dallas",
}));
}
}
Observations:
I have added logging to the entry and exit of the getCities and setCities methods. During refresh of the JSF page, the getCities method gets called. However, when submitting, the setCities never gets called.
I do not get any errors or exceptions in the console log (javax.faces.PROJECT_STAGE set to DEVELOPMENT in web.xml).
No errors are being passed to <h:messages/>
set methods do not get called for any form input fields. The page behaves 'odd'.
The issue seems similar to Issue #3 on the accepted answer from commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated, however I do not have an apparent conversion problem for <p:selectCheckboxMenu>. As per documentation it should be able to handle a List<String> perfectly.
So in addition to fixing the obvious problem, how can we make sure any errors related to this are made visible, rather than having this silent type of failure?
In short, <f:viewParam> does not yet support list of values.
The signature of the cities property is List<String>.
Note that when we are trying to pass a parameter for cities (append ?cities=Dallas to the end of the request URL), we suddenly do get an appropriate conversion error in <h:messages/> stating:
Conversion Error setting value 'Dallas' for 'null Converter'.
Also as per referenced posts, we should also include the messages for ajax updates:
<h:commandButton value="Submit">
<f:ajax execute="#form" render="output"/>
<f:ajax execute="#form" render="messages"/>
</h:commandButton>
When following this, not during first visit, but at least during submit we get an appropriate error:
Conversion Error setting value '[]' for 'null Converter'.
I am not sure why the <f:viewParam>'s need to be set during an ajax-style submit though?
To solve, you can either provide a <f:converter>, or provide additional getter/setters that handles setting/getting the Array or List type based on a String.
Picking a quick solution we can change the <f:viewParam> as follows:
<f:viewParam name="cities" value="#{myBean.citiesCsv}" />
While for the backing bean, we add following method:
public void setCitiesCsv(String csv) {
if (csv.isEmpty()) {
cities = new ArrayList<>();
} else {
cities =
Stream.of(csv.split(","))
.collect(Collectors.toCollection(ArrayList<String>::new));
}
}
For repeated such efforts, we should probably consider an appropriate converter to be used instead, which we can custom build for simple CSV conversions if it suits our purpose.
Related posts
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated (Item #3)
Distinguish between conversion failure and validation failure in o:viewParamValidationFailed
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

commandButton doesn't invoke managed bean action

I've been reading and searching among the many pages with similar questions, but I cannot find why my commandButton is not invoking the action (I have debugged it and that is the problem). My code looks simple but... doesn't work. Maybe it's a newbie problem, but I don't know where it is.
I'm writing a portlet for liferay using JSF2 and Liferay Faces Alloy.
I've also read the question commandLink/commandButton/ajax backing bean action/listener method not invoked, very educational for me, but none of the points have solved my problem.
Here is my mainView.xhtml file:
<?xml version="1.0"?>
<f:view
xmlns="http://www.w3.org/1999/xhtml"
xmlns:aui="http://liferay.com/faces/aui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<h:messages globalOnly="true" layout="table" />
<h:outputText id="esteTexto" value="#{ramSession.texto}" />
<br />
<h:commandButton action="#{ramSession.add}" styleClass="btn btn-default" value="#{ramSession.texto}">
</h:commandButton>
</h:form>
</h:body>
</f:view>
And here is my SessionScoped ManagedBean file, RamSession.java:
#ManagedBean
#SessionScoped
public class RamSession extends AbstractBaseBean implements Serializable {
private static final long serialVersionUID = 919724848720360000L;
private String texto;
public void add() {
this.texto = new String("Entrando");
}
#PostConstruct
public void postConstruct() {
this.texto = new String("Jereje");
}
public String getTexto() {
logger.info("gettingTexto");
addGlobalSuccessInfoMessage();
return this.texto;
}
public void setTexto(String texto) {
this.texto = texto;
}
}
I have also tried returning a String (even not necessary), with an actionListener method and even with ajax but nothing. Can anybody help me? Thanks a lot.
Maybe your mojarra listner is not configured correctly.
Follow one of the two following sub-steps
a. Add the liferay-faces-init.jar dependency in each Liferay JSF project by adding the following code to each pom.xml :
<dependency>
<groupId>com.liferay.faces</groupId>
<artifactId>liferay-faces-init</artifactId>
<version>3.1.3-ga4</version>
</dependency>
b. Add the following code in each WEB-INF/web.xml of all your JSF projects :
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
Why not initialize texto in the declaration?
private String texto = "Jereje";
public void addGlobalSuccessInfoMessage(){
//faces message
}
//Getter Setter
Then you can remove the entire PostConstruct method.
Also if all you want to do is set a string and update without navigation just use f:setPropertyActionListener with a f:ajax for updating your messages. You can use action if you want by returning null or void, or actionListener and set the string inside of that, but I'm not seeing why you'd want to. This link may help with those options... Answer by Balus C.
May want to remove any extra logic from your getter method as well. This won't affect your problem but it's cleaner and creating a success message on a getter seems problematic.
<h:form id="myForm">
<h:messages globalOnly="true" layout="table" />
<h:outputText id="esteTexto" value="#{ramSession.texto}" />
<br />
<h:commandButton value="#{ramSession.texto}" actionListener="#{ramSession.addGlobalSuccessInfoMessage()}" styleClass="btn btn-default">
<f:setPropertyActionListener value="Entrando" target="#{ramSession.texto}" />
<f:ajax render="myForm" />
</h:commandButton>
</h:form>

f:ajax listener method argument

TODO: Get selected row in h:datatable.
Code Snippet using HtmlDataTable binding:
<h:dataTable value="#{bean.licenses}" var="license" rendered="#{!empty bean.licenses}" binding="#{bean.dataTable}">
<h:column>
<h:selectOneRadio onclick="uncheckOthers(this);" >
<f:selectItem itemValue="null" />
<f:ajax listener="#{bean.updateSelected}" render="licenseGenerator:submitButtons">
<f:param name="license" value="#{license}" />
</f:ajax>
</h:selectOneRadio>
</h:column>
</h:dataTable>
So the above mentioned is one way to do it, however since I am already using EL 2.2, I was trying to do something like the accepted answer. and update f:ajax to
<f:ajax listener="#{bean.updateSelected(license)}" render="licenseGenerator:submitButtons">
When I update the code with the above code, the listener is not getting invoked so I checked the documentation which says:
javax.el.MethodExpression (signature must match public void
processAjaxBehavior(javax.faces.event.AjaxBehaviorEvent event) throws
javax.faces.event.AbortProcessingException)
So, basically with the above signature I can't use something like
public void listener(License license){
//...
}
However, since it was the accepted answer, I am sure I am missing something here. Thanks for the help!
JSF Version: Mojarra JSF Implementation 2.2.12
Server: Apache Tomcat 8.0.24

Why am I getting a NullpointerException on CommandLink click in JSF

I am trying to trigger a method in the backing bean on load.
Whenever the link is clicked it throws a NPE , any idea why?, I've included snippets of my code below.
Error: listener="#{userController.validate}": java.lang.NullPointerException: javax.el.ELException
<h:form id="reg">
<h:outputLabel value="Promo" /> :
<h:inputText id="promocode" value="#{userController.promocode}">
<f:ajax render=":promoimage" event="blur" listener="#{userController.validate}"/>
</h:inputText>
<h:commandLink id="dummyclick" value="link">
<f:ajax event="click" render=":promoimage" listener="#{userController.validate}"/>
</h:commandLink>
</h:form>
#ManagedBean(name = "userController", eager= true)
#SessionScoped
public class UserController implements Serializable {
public void validate(AjaxBehaviorEvent event){
........
}
}
<script type="text/javascript">
document.getElementById("reg:dummyclick").click();
</script>
I removed the ajax call and it worked, it was probably pointless in this case. I'd still like to know why it is throwing an NPE though.
<h:commandLink id="dummyclick" value="link" action="#{userController.showPromo}">
</h:commandLink>
.......
<script type="text/javascript">
document.getElementById("reg:dummyclick").click();
</script>
Why you using command link, instead of that use command button and if you set required="true" for inputtext, it will automatically check validation on same button.

JSF does not convert InputText value to string variable of backing bean without custom converter

I try learn JSF and faced with problem.
I did use Servlet 2.5, JDK 1.6 and JSF 2.0.6 (com.sun.faces version from pom file).
I have a simple JSF page that has a <h:inputText/> tag for interaction with user
I expect what user fill this h:inputText then click on h:commandButton and on server side i will get backing bean with updated value.
But in my case lifecycle of JSF breaks on process validations, move to render
response and show to user "Parser error!" message
I.e. for simple h:inputText without any validator and converter i receive error message from server side about parsing of h:inputText value.
After some time i figured out what i can create my own converter which will not modify object, just pass String through himself.
I did add my realization of converter to <h:inputText/> and this work.
Question:
In all examples in books and other tutorials nobody used custom converter for <h:inputText/> if inputText is representation of String value of backing bean.
Why all of this tutorials and examples not working for me without custom converter? Where my mistake?
Source codes:
index.xhtml without converter, not worked for me:
<h:form id="UserForm">
<h:outputText value="Insert your first name:" />
<h:inputText id="userNameID" required="true" value="#{userBean.firstName}">
<f:validateLength minimum="5" maximum="25" />
</h:inputText>
<h:message showSummary="true" showDetail="false" for="userNameID" />
<h:commandButton id="submit" action="/view/validator/response?faces-redirect=true"
value="Submit" />
</h:form>
UserBean.java:
#ManagedBean(name = "userBean")
#SessionScoped
public class UserBean implements Serializable {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
MyConverter.java - dummy converter
#FacesConverter(value = "myConverter")
public class MyConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
index.xhtml with converter, worked as expected:
<h:form id="UserForm">
<h:outputText value="Insert your first name:" />
<h:inputText id="userNameID" required="true" value="#{userBean.firstName}" converter="myConverter">
<f:validateLength minimum="5" maximum="25" />
</h:inputText>
<h:message showSummary="true" showDetail="false" for="userNameID" />
<h:commandButton id="submit" action="/view/validator/response?faces-redirect=true"
value="Submit" />
</h:form>
The cause of the problem is not visible in the code posted so far, but the key symptom "it fails with a message coming from a so far unidentified converter while it succeeds with an explicit converter" suggests that you've elsewhere in the same project a #FacesConverter(forClass=String.class) which would run automatically on every single String property which doesn't have another converter explicitly specified.

Resources