Interesting case. For everyone, the following minimal code reproduces this:
Facelet:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<f:metadata>
<f:viewParam id="id" name="id" value="#{viewParamBean.id}"/>
</f:metadata>
<h:body>
<h:messages />
#{viewParamBean.id} <br/>
<h:form>
<h:inputText value="#{viewParamBean.text}" >
<f:validateLength minimum="2"/>
</h:inputText>
<h:commandButton value="test" action="#{viewParamBean.actionMethod}"/>
</h:form>
</h:body>
</html>
Bean:
@ManagedBean
@RequestScoped
public class ViewParamBean {
private long id;
private String text;
public void actionMethod() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
If you call the Facelet with viewparam.xhtml?id=12
it will display the 12
onscreen. If you then input something valid, e.g. aaaaa
, the id will disappear from the URL, but keeps being displayed on screen (owning to the stateful nature of ui components).
However... as OP mentioned, as soon as any validator error occurs (e.g. entering a
), the id will be permanently lost. Entering valid input afterwards will not bring it back. It almost seems like a bug, but I tried both Mojarra 2.1 and Myfaces 2.1 and both have the same behavior.
Update:
After some inspection, the problem seems to be in this method of `UIViewParameter' (Mojarra):
public void encodeAll(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
// if there is a value expression, update view parameter w/ latest value after render
// QUESTION is it okay that a null string value may be suppressing the view parameter value?
// ANSWER: I'm not sure.
setSubmittedValue(getStringValue(context));
}
And then more specifically this method:
public String getStringValue(FacesContext context) {
String result = null;
if (hasValueExpression()) {
result = getStringValueFromModel(context);
} else {
result = (null != rawValue) ? rawValue : (String) getValue();
}
return result;
}
Because hasValueExpression()
is true, it will try to get the value from the model (the backing bean). But since this bean was request scoped it will not have any value for this request, since validation has just failed and thus no value has ever been set. In effect, the stateful value of UIViewParameter
is overwritten by whatever the backing bean returns as a default (typically null, but it depends on your bean of course).
One workaround is to make your bean @ViewScoped
, which is often a better scope anyway (I assume you use the parameter to get a user from a Service, and it's perhaps unnecessary to do that over and over again at every postback).
Another alternative is to create your own version of UIViewParameter
that doesn't try to get the value from the model if validation has failed (as basically all other UIInput
components do).
includeViewParams=true
in your submit action? – Sweltering