Using multiple <f:viewParam> on a JSF page along with custom converters and ignoring only invalid parameters whose conversion fails

StackOverflow https://stackoverflow.com/questions/18576083

  •  27-06-2022
  •  | 
  •  

Pregunta

I have two <f:viewParam> tags enclosed within an <f:metaData> tag on a JSF page as shown below.

The index.xhtml file:

<h:form id="form" prependId="true">
    <f:metadata>
        <f:viewParam name="userId" id="paramId" rendered="#{not empty param.userId}" converter="#{userRoleConverter}" value="#{testManagedBean.userTable}"/>                
        <f:viewParam name="userRoleId" id="userParamId" rendered="#{not empty param.userRoleId}" converter="#{userAuthorityRowSelectionConverter}" value="#{testManagedBean.entity}"/>
        <f:event type="preRenderView" listener="#{testManagedBean.preRenderEvent}" />
    </f:metadata>
    <p:messages id="messages" globalOnly="false" showDetail="true" showSummary="false" autoUpdate="false" closable="true"/>
</h:form>

each of them is associated with a converter as specified by the converter attribute.

When two parameters namely userId and userRoleId are appended as a querystring to the URL, two properties namely userTable and entity are set to the associated managed bean - testManagedBean after conversion is taken place by the converters specified.

The managed bean:

@ManagedBean
@ViewScoped
public final class TestManagedBean implements Serializable
{
    private UserRoles entity;    //Both are POJOs.
    private UserTable userTable;

    public TestManagedBean(){}

    //Setters and getters of both the properties entity and userTable.        

    public void preRenderEvent(ComponentSystemEvent event) throws AbortProcessingException
    {
        System.out.println((entity==null)+" : "+(userTable==null));
    }
}

When conversion fails on one of the properties, either userId or userRoleId, the other property along with the failed one is also not set to the managed bean (which is expected to be set because the conversion of this other property is not likely to fail) and both of them are null.

For example, if I entered a URL like,

/index.jsf?userId=100&userRoleId=12

then, the following statement in the preRenderEvent() method (associated with <f:event>),

System.out.println((entity==null)+" : "+(userTable==null));

displays true : true.

In this case, the conversion of userId fails (the value 100 doesn't exist in the database) but the conversion of userRoleId should succeed (but it doesn't) and shouldn't be null (which exists in the database).


Similarly, the following URL,

/index.jsf?userId=1&userRoleId=120

again displays true : true.

It is the reverse case of the previous one. userId exists in the database but userRoleId doesn't.


Finally, the following URL,

/index.jsf?userId=1&userRoleId=12

shows false : false. The values of both of the parameters in this case exist in their respective table in the database.

The failure of conversion is notified by throwing ConverterException that need not mention.


So, why is the value of both the properties set to null, when the conversion of one of them fails? Is only one of the converters executed, when conversion of one of them fails?

¿Fue útil?

Solución

You shouldn't use a converter to validate, but a validator. Let the converter return null if nothing can be found (and throw ConverterException only if value is not interpretable as an user ID, i.e. it's inconvertible). Use required="true" instead if you'd like the value to be non-null.

E.g.

if (value == null) {
    return null;
}

if (!value.matches("[0-9]+")) {
    throw new ConverterException("Supplied parameter value can't be interpreted as an user ID.");
}

return service.getById(Long.valueOf(value)); // May return null if it doesn't exist.

By the way, the rendered attribute isn't making any sense there on <f:viewParam>. That's a taghandler which builds JSF component tree, not an UI component which renders some HTML. Even more, it's not documented at all. Also, it's somewhat strange to see <f:metadata> nested inside a form. Refer When using <ui:composition> templating, where should I declare the <f:metadata>?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top