JSF 2 : Bean Validation JSR 303 notnull : The model value is returned - jsf-2.2

I am using JSF 2 (MyFaces 2.2.9) and Bean Validation (Hibernate Validator 5.2.2.Final).
I use the #NotNull annotation on a bean that is a property of my managed bean.
(ManagedBean class)
#ManagedBean
public class ConfiguracionesBean {
private Configuraciones configuraciones;
#PostConstruct
public void postConstruct() {
this.configuraciones = Configuraciones.find();
}
//getters/setters/unrelevant code
...
}
(Bean class)
public class Configuraciones {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
private String name;
}
(.xhtml page)
<h:outputLabel for="name">#{i18n['name']}</h:outputLabel>
<h:inputText id="name" label="#{i18n['name']}" value="#{configuracionesBean.configuraciones.name}" />
<h:message for="name" errorClass="error" warnClass="warn" infoClass="info"/>
The first time the page is displayed, the "name" input text field contains the value that was previously stored in my database (normal until here).
If I delete this value on the html form, and I submit, then the #NotNull constraint is triggered, and I get an error (still normal here).
But the value of the inputText displayed on the html page is the value from the managed bean as it was initialized). Not the "empty" value that the user just put (by emptying the field). So the user sees an error "The field can not be null", but the field actually contains the previous value.
Is there a way to prevent this? I want the input to be empty, as it is what the user put.
I precise that I have the option :
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
Thanks in advance for you answers.
Note : I would really like to stick with the validations only done by JSR 303, as like this I have a uniform way of dealing with constraints. So no JSF validators (that could do the same, I know).
Alex

This is the normal behaviour. Validations are processed in JSF's "Process Validations Phase". This phase is computed before the "Update Model Values" phase. That means if validation fails your model (Bean) won't be updated with the invalid values. All phases after "Process Validations Phase" will be skipped and "Render Response Phase" will be executed. The result is that when your invalid field is rerendered it will still show the old value because the model has not been updated.
In the "Render Response Phase" you will now be able to show an error message with <h:messages>. The only way I can think of to prevent old model values from showing is using the ajax-Element and not rendering the input element in the render response phase but instead just rendering its error message.
So in your xhtml:
<h:outputLabel for="name">#{i18n['name']}</h:outputLabel>
<h:inputText id="name" label="#{i18n['name']}" value="#{configuracionesBean.configuraciones.name}">
<f:ajax event="valueChange" render="errorBlock" />
</h:inputText>
<h:panelGroup id="errorBlock">
<h:message for="name" errorClass="error" warnClass="warn" infoClass="info"/>
</h:panelGroup>
The following links might be helpful
JSF life cycle illustrated: http://developersbook.com/jsf/images/JSF-Lifecycle.png
JSF life cycle: https://docs.oracle.com/javaee/1.4/tutorial/doc/JSFIntro10.html#wp122256

Related

Richfaces Datatable loses submitted value of inputs on validation fail

I have two inputs - one inside a "normal" h:dataTable and one inside a rich:dataTable When I submit a wrong value, i.e. validation fails, the "normal" one keeps the value I submitted while the second one loses it. See the following code snippets (enter any value an press the button):
ManagedBean
#ManagedBean
#ViewScoped
public class TestController implements Serializable {
private static final long serialVersionUID = -484022507596298941L;
private String[] stringArray1 = {"Element 1", "Element 2"}; // + Getter
private String[] stringArray2 = {"Element A", "Element B"}; // + Getter
private Map<String, String> inputValues = new HashMap<String, String>(4); // + Getter
public TestController() {
inputValues.put(stringArray1[0], "");
inputValues.put(stringArray1[1], "");
inputValues.put(stringArray2[0], "");
inputValues.put(stringArray2[1], "");
}
public void doSomething() {
System.out.println("Did something");
}
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) {
throw new ValidatorException(new FacesMessage("This can never be valid."));
}
}
View
<h:form>
<h1>h:dataTable</h1>
<h:dataTable id="table1" value="#{testController.stringArray1}" var="string" columnClasses="inactive">
<h:column>
<h:outputText value="#{string}:"/>
<h:inputText id="someInput" value="#{testController.inputValues[string]}" validator="#{testController.validate}"/>
<h:message for="someInput" id="msg" style="color: red;"/>
</h:column>
</h:dataTable>
<h1>rich:dataTable</h1>
<rich:dataTable id="table2" value="#{testController.stringArray2}" var="string">
<rich:column>
<h:outputText value="#{string}:"/>
<h:inputText id="someInput" value="#{testController.inputValues[string]}" validator="#{testController.validate}"/>
<h:message for="someInput" id="msg" style="color: red;"/>
</rich:column>
</rich:dataTable>
<h:commandButton id="button" action="#{testController.doSomething}" value="do something"/>
</h:form>
Is this known Richfaces behaviour or a bug of some kind? Is there a way to make it behave the same way the normal JSF-DataTable does? Using h:dataTable instead is not always an option and losing your "I-was-just-about-to-correct-it" input is rather annoying.
ADDITION:
I just checked the behaviour of ui:repeat and a4j:repeat and it's just the same: ui:repeat keeps the submitted value while a4j:repeat does not.
UPDATE: Re-worked example code to rule out some possible problems as mentioned in comments (input fields now point to different values; only one form element).
Tested on Mojarra 2.1.21 with RichFaces 4.3.7 and JBoss AS 7 plus on Mojarra 2.2.7 with RichFaces 4.5.0 Alpha3 and JBoss Wildlfy - same result.
I just tried each form of your page separately with Richefaces 4.3.7 and Mojarra 2.2.6 and it's perfectly working! i didn't noticed any abnormal behavior, when validation fails i didn't lost any values. That means that there is no Validation issues with the Richfaces components.
However, When using the two forms in a single page, i can notice that when i submit the first form the inputText of the second form loses it's value, while if we submit the form2 the inputText of the first form don't lost it's value, in my guess its because JSF stored the state of it's HTML components in the javax.faces.ViewState and doesn't do the same for Richfaces components, using Firebug you can easily verify that the only common request parameter between those two POST requests is the javax.faces.ViewState.

Keep bean attributes after ajax form submit

I have a #ViewScoped #ManagedBean which creates an unique ID. This ID is rendered in a form like:
<h:form>
<h:outputText value="#{myBean.uid}" id="uid"/>
<h:hiddenInput value="#{myBean.uid}" id="hiddenId" />
....
<p:commandButton actionListener="#{myBean.create}" ajax="true" update="#form" value="Create" />
</h:form>
So far so good. On first request the page is rendered correctly. After submitting the form and in the case of validation failure, the outputText is empty but the hidden input field keeps its variable.
Any clue what I'd have to do to prevent this behavior and too let the outputText keep its state?
I realized that the bean seems to be initialized after each ajax request. But then, why does the hidden input field keeps the old variable?
Here is the relevant code of my bean:
#ManagedBean(name = "myBean", eager = true)
#Stateful
#Model
#ViewScoped
public class MyBean implements Serializable {
...
private String uid;
...
#PostConstruct
public void initWithData() {
this.uid = UUID.randomUUID().toString();
}
}
JSF input components have 3 places where the value (the state) is stored:
Submitted value (the raw unconverted/unvalidated String request parameter value).
Local value (the successfully converted/validated object value, stored inside component itself).
Model value (when the entire form is successfully processed, stored as bean property)
JSF processes input components as follows:
Get HTTP request parameter value by component's client ID and store it as submitted value.
If conversion/validation succeeds, set it as local value and set submitted value to null.
If entire form is successfully processed, set it as model value and set local value to null.
JSF renders values of input components as follows:
If submitted value is not null, display it.
Else if local value is not null, display it.
Else display model value.
So, in your particular case of a general validation failure, JSF is for that hidden input component just redisplaying the local value instead of the model value. If you want to achieve the same with the output text, I think best is to just do the same as JSF:
<h:outputText value="#{empty hiddenId.submittedValue ? empty hiddenId.localValue ? hiddenId.value : hiddenId.localValue : hiddenId.submittedValue}" />
<h:inputHidden id="hiddenId" binding="#{hiddenId}" value="#{myBean.uid}" />
Alternatively, you could just use a read only input and remove the border by CSS if necessary:
<h:inputText id="hiddenId" value="#{myBean.uid}" readonly="true" style="border: none;" />
As to your bean, I'm not sure what's happening there as this class seems to be extremely tight coupled. I'd rather split it into 3 classes: one real backing bean, one stateless service and one model entity. Further, you should also make sure that you aren't binding view build time tags or attributes to a property of a view scoped bean. Otherwise it will indeed guaranteed be reconstructed on every single request.
See also:
JSTL in JSF2 Facelets... makes sense?
#PostConstruct method is called even if the ManagedBean has already been instantiated (e.g. on AJAX-calls)
By the way, the eager=true has only effect in #ApplicationScoped beans.
The problem is probably the #Model stereotype (was, as you already removed it). It combines #Named and #RequestScoped and makes the bean a CDI request scoped bean. CDI managed beans should be resolved before JSF managed beans and therefore the #ViewScoped has no effect (it creates a JSF managed bean).

Not able to validate input text field rendered using ajax in jsf 2.0

<h:form>
<h:selectManyMenu id="carsList"
value="#{bean.carList}"
style="width:400px; height:100px" label="List">
<f:selectItems value="#{bean.cars}" var="i"
itemLabel="#{i.code}" itemValue="#{i.Name}" />
<f:selectItem itemLabel="Other" itemValue="other"/>
<f:ajax event="change" execute="#this" render="othermodel"/>
</h:selectManyMenu>
<br></br>
<h:panelGroup id="othermodel">
<h:outputText value="Others:" style="margin-top:10px;color:red;font-weight:bold;"
rendered="#{bean.carList.contains('other')}" />
<h:inputText size="50" id="otherinput" required="true"
rendered="#{bean.carList.contains('other')}"/>
<h:message for="otherinput"></h:message>
</h:panelGroup>
<h:commandButton value="Next" action="#{bean.submitForm}"/>
</h:form>
My bean is requestScoped and when my carList has a value other i am able to show the panelGrid but when user don't enter any value in the input field rendered using AJAX , even i specificed required=true but it's not getting validated. And value of the input text box is null in the backend code.
How can I do the validation for the input field rendered using AJAX and why my value is coming as null? I am using JSF 2.0
The rendered attribute is re-evaluated during the request of the form submit. Your bean is request scoped and thus recreated on every single request (also ajax requests) with all properties set to default. So the carList property will also be emptied and the rendered attribute would evalute false before the update model values phase has filled the carList. So, for JSF, the <h:inputText> is never rendered and thus it won't be processed.
Put the bean in the view scope instead. It'll live as long as you interact with the same view by (ajax) postbacks. It's the right scope for dynamic ajax based forms with a lot of conditional rendering.
See also:
How to choose the right bean scope?
I tried this with #ViewScope. When I made my Spring managed service as transient I was getting null reference after deserialization. So, i tried the below method to get the Spring Service.
#ManagedBean(name="bean")
#ViewScoped
public class Bean implements Serializable {
#ManagedProperty(value="#{appService}")
private transient AppService appService;
// Getting AppService Object which is singleton in the application during deserialization
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
FacesContext context = FacesContext.getCurrentInstance();
appService = (AppService)context.getApplication()
.evaluateExpressionGet(context, "#{appService}", AppService.class);
stream.close(); // not sure i have to do this
}
}
This is working for me without any issues.

Avoid validation of #Size annotation in JPA

I have a JPA entity with the following attribute:
public class Person implements Serializabe {
...
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "name", nullable = false, length = 45)
private String name;
...
And it's view:
<h:outputLabel value="Name: "/>
<h:inputText id="name"
value="#{personBean.person.name}"
validator="#{personValidator.validate}"/>
<rich:message for="name"/>
The personValidator checks if 0 < name.length < 45 and if it already exists in the database; it works fine. When I try do add an empty name, or bigger than 45 chars, I get my correct validator message but in the Glassfish output is shown:
INFO: WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
sourceId=contentForm:name[severity=(ERROR 2), summary=(size must be between 1 and 45), detail=(size must be between 1 and 45)]
I have tried adding <validation-mode>NONE</validation-mode> to my persistence.xml but no effect. How do I avoid this #Sizeannotation validation?
The message you're seeing is because a faces message (likely originating from a validator) has been emitted, but likely has not been displayed.
In this case, the #Size annotation is from Bean Validation and is processed by both JPA and JSF.
Unless you manually generated the message from your backing bean (by e.g. putting a try/catch around your business logic) this one is really coming from JSF and disabling anything in JPA's persistence.xml won't make a difference.
You can disable the JSF validation by nesting an f:validateBean tag inside your input components and setting the disabled attribute to true. See Temoporarily suppress beanvalidation with JSF
You can disable the validation for the specific input by adding a validateBean tag:
<h:outputLabel value="Name: "/>
<h:inputText id="name"
value="#{personBean.person.name}"
validator="#{personValidator.validate}">
<f:validateBean disabled="true"/>
</h:inputText>
<rich:message for="name"/>

set property of BackingBean from the view (no action event with GET request components)

imagine there is BeanA bound to ViewA.xhtml and BeanB bound to ViewB.xhtml. BeanA and BeanB are backing beans with just one attribute per bean: "Object obj;" with getters and setters.
Now i am in ViewA doing the following:
<ui:repeat value="#{someOtherBean.listOfObjects}" var="objSelected">
<h:commandLink value="someValue" action="ViewB">
<f:setPropertyActionListener target="#{beanB.obj}" value="#{objSelected}" />
</h:commandLink>
</ui:repeat>
This works great! I iterate through a List and the object i click on (via commandLink) is set into BeanB.
Problem: I need to work with a GET Request, so i have so use h:link or h:outputLink (btw, where is the difference?). But doing so, i can't use the f:setPropertyActionListener component, because a GET request does not fire an action event.
Since there is no action event i have to use a GET request, giving the ID of the object to BeanB as a parameter. BeanB then uses a dao to get the object with the specified ID. But this sux. I don't want to use the dao. So my specific question:
What is the equivalent to f:setPropertyActionListener for GET request links? How can I set a property of a BackingBean when I click on a h:link or h:outputLink component?
I hope there is a solution, thanks in advance.
Pass it as a request parameter. Request parameters can be only strings, so you need to convert it (or better, the smallest possible part which uniquely identifies the object in question) to string first.
Here's an example which uses the (database) identifier of the object for this:
<ui:repeat value="#{someOtherBean.listOfObjects}" var="objSelected">
<h:link outcome="ViewB">
<f:param name="id" value="#{objSelected.id}" />
</h:link>
</ui:repeat>
And in BeanB add:
#ManagedProperty("#{param.id}")
private Long id;
private SomeObject objSelected;
#PostConstruct
public void init {
objSelected = objService.find(id);
}
// ...

Resources