javaee / mojarra

PLEASE NOTE: This project has moved to Eclipse Foundation and will be archived under the JavaEE GitHub Organization. After Feb. 1, 2021, the new location will be github.com/javaee/mojarra. Mojarra - Oracle's implementation of the JavaServer Faces specification
https://github.com/eclipse-ee4j/mojarra
Other
164 stars 58 forks source link

"Interpret empty string submitted value as null" must also be considered in HtmlBasicRenderer#getCurrentValue() #2266

Closed javaserverfaces closed 11 years ago

javaserverfaces commented 12 years ago

Consider this testcase:

<h:form>
    <h:inputText value="#{bean.input}" required="true" />
    <h:commandButton value="submit" />
    <h:messages />
</h:form>

with

private String input = "input";
// Getter+Setter

When you remove the value, the "value is required" validation error appears, which is perfectly fine. Also note that the input field is kept blank, as the enduser originally entered, which makes totally sense.

However, when you add this context parameter (which is often done to avoid the non-required model values being cluttered with empty strings and/or in order to be able to use JSR303 tt>@NotNull</tt annotation)

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>false</param-value>
</context-param>

then the initial model value is redisplayed on validation error instead of the submitted value.

The culprit is in HtmlBasicRenderer#getCurrentValue().

if (component instanceof UIInput) {
    Object submittedValue = ((UIInput) component).getSubmittedValue();
    if (submittedValue != null) {
        // value may not be a String...
        return submittedValue.toString();
    }
}

One possible solution would be to check as well if it is invalid:

if (component instanceof UIInput && !((UIInput) component).isValid()) {
    Object submittedValue = ((UIInput) component).getSubmittedValue();
    if (submittedValue != null) {
        // value may not be a String...
        return submittedValue.toString();
    } else {
        return null;
    }
}

This is actually also more in line with the normal behaviour of UIInput#validate() method.

Environment

Mojarra 2.1.4

Affected Versions

[2.1.3]

javaserverfaces commented 12 years ago

Reported by @BalusC

javaserverfaces commented 12 years ago

bfrevel said: I have the same behavior in all components. For example the selectOneMenu component.

This is my testcase:

**TestBean.java**public class TestBean {
    @NotNull
    private String stringValue1;
    @NotNull
    private String stringValue2;
    @NotNull
    private Integer integerValue;

    //getter and setter methods 
    private void init() {
    stringValue1 = "test";
    stringValue2 = "String1";
    integerValue = 1;
    }

    public TestBean() {
    this.init();
    }
}
**page1.xhtml**...
<h:outputLabel value="StringValue1:" for="stringValue1" />
<h:inputText id="stringValue1" value="#{testBean.stringValue1}" />

<h:outputLabel value="StringValue2:" for="stringValue2" />
<h:selectOneMenu value="#{testBean.stringValue2}" id="stringValue2">
    <f:selectItem itemLabel="null" noSelectionOption="true" />
    <f:selectItem itemLabel="String1" itemValue="String1" />
    <f:selectItem itemLabel="String2" itemValue="String2" />
</h:selectOneMenu>

<h:outputLabel value="IntegerValue:" for="integerValue" />
<h:selectOneMenu value="#{testBean.integerValue}" id="integerValue">
    <f:selectItem itemLabel="null" noSelectionOption="true" />
    <f:selectItem itemLabel="Integer1" itemValue="1" />
    <f:selectItem itemLabel="Integer2" itemValue="2" />
</h:selectOneMenu>

<h:commandButton id="save" action="#{testBean.save}" value="Save" />
...

For all components and values we have the same behavior. If you select the null value and submit the form, JSF will redisplay the old value and not the submitted value.

javaserverfaces commented 12 years ago

wemu said: I've used the patch above and the described issue disappears. I've only tested it with inputText components, if I stumble across a selectMenu i'll try that out too.

javaserverfaces commented 12 years ago

rogerk said: Did you mean "true" for javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL context param? When it is "false", there is no problem.

javaserverfaces commented 12 years ago

wemu said: yes that is written in the description and also true in my environment.

meanwhile: I tried mojarra 2.1.6 and I cannot reproduce this issue there. Although the patch here was not added something else must have changed.

javaserverfaces commented 12 years ago

@BalusC said: Yes, I meant to write true, sorry for the confusion. I can't edit the original ticket anymore.

Another, maybe better, way to fix this issue is to alter UIInput#getSubmittedValue():

public Object getSubmittedValue() {
    if (submittedValue == null && !isValid() && considerEmptyStringNull(FacesContext.getCurrentInstance())) {
        return "";
    }
    else {
        return submittedValue;
    }
}

This way the component libraries which rely on UIInput doesn't need to change their renderers.

javaserverfaces commented 11 years ago

rogerk said: See specification issue: http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-939

javaserverfaces commented 11 years ago

cagatay_civici said: considerEmptyStringNull must be considered, without it the initial proposed patch will fail for a case like;

<h:inputText id="name" value="#{bean.input}" />

<h:inputText id="sname" value="#{bean.input2}" required="true" />

<h:commandButton id="btn" value="Submit" />

If name is cleared and form is submitted, validation error happens because of sname field but name still displays "input" model value.

I haven't tested Balusc's improved patch in last comment.

javaserverfaces commented 11 years ago

cagatay_civici said: The patch I added to PrimeFaces is;

if(component instanceof EditableValueHolder) {
EditableValueHolder input = (EditableValueHolder) component;
Object submittedValue = input.getSubmittedValue();

if(ComponentUtils.considerEmptyStringAsNull(context) && submittedValue == null && context.isValidationFailed()) {
    return null;
}
else if(submittedValue != null) {
    return submittedValue.toString();
}
}

So we need to check if another input or current input itself caused validation error as well.

javaserverfaces commented 7 years ago

This issue was imported from java.net JIRA JAVASERVERFACES-2262

javaserverfaces commented 11 years ago

Marked as won't fix on Thursday, November 1st 2012, 9:51:07 am