jsf - includeViewParams=true converts null model value to empty string in query string -


given <p:selectonemenu> follows.

<f:metadata>     <f:viewparam name="id" value="#{testmanagedbean.id}" converter="javax.faces.long"/> </f:metadata>  <p:selectonemenu value="#{localebean.language}" onchange="changelanguage();">     <f:selectitem itemvalue="en" itemlabel="english" />     <f:selectitem itemvalue="hi" itemlabel="hindi" /> </p:selectonemenu>  <p:remotecommand action="#{testmanagedbean.submitaction}"                  name="changelanguage"                  process="@this"                  update="@none"/> 

the corresponding managed bean :

@managedbean @requestscoped public final class testmanagedbean {      private long id; //getter , setter.      public testmanagedbean() {}      public string submitaction() {         return facescontext.getcurrentinstance().getviewroot().getviewid() + "?faces-redirect=true&includeviewparams=true";     } } 

the parameter indicated <f:viewparam> optional. page, example accessed using url follows.

https://localhost:8181/project-war/private_resources/test.jsf

since id optional parameter, empty parameter attached url (when language changed <p:selectonemenu>), in case not supplied follows.

https://localhost:8181/project-war/private_resources/test.jsf?id=

this should not happen. empty parameter should not appended, if not supplied , url should first one.

is there way prevent empty parameter being appended url, when not passed?


this associated converter specified <f:viewparam> - javax.faces.long.

if converter removed then, parameters not appended url, in case no parameters supplied.

although specifying converter demonstrated here unnecessary, have converters shown below convert id passed though url query-string parameter jpa entity.

@managedbean @requestscoped public final class zoneconverter implements converter {      @ejb     private final sharablebeanlocal sharableservice = null;      @override     public object getasobject(facescontext context, uicomponent component, string value) {         try {             long parsedvalue = long.parselong(value);              if (parsedvalue <= 0) {                 throw new converterexception(new facesmessage(facesmessage.severity_error, "message summary", "message"));             }              zonetable entity = sharableservice.findzonebyid(parsedvalue);             if (entity == null) {                 throw new converterexception(new facesmessage(facesmessage.severity_warn, "message summary", "message"));             }              return entity;         } catch (numberformatexception e) {             throw new converterexception(new facesmessage(facesmessage.severity_error, "message summary", "message"), e);         }     }      @override     public string getasstring(facescontext context, uicomponent component, object value) {         return value instanceof zonetable ? ((zonetable) value).getzoneid().tostring() : "";     } } 

this converter required specified explicitly <f:viewparam> follows.

<f:viewparam name="id"               value="#{testmanagedbean.id}"              converter="#{zoneconverter}"              rendered="#{not empty param.id}"/> 

and associated managed bean needs changed follows.

@managedbean @requestscoped public final class testmanagedbean {      private zonetable id;  //getter , setter.      public testmanagedbean() {}      public string submitaction() {         return facescontext.getcurrentinstance().getviewroot().getviewid() + "?faces-redirect=true&includeviewparams=true";     } } 

this oversight in mojarra's default implementation of uiviewparameter#getstringvaluefrommodel() source reference copypasted below:

384    public string getstringvaluefrommodel(facescontext context) 385        throws converterexception { 386        valueexpression ve = getvalueexpression("value"); 387        if (ve == null) { 388            return null; 389        } 390 391        object currentvalue = ve.getvalue(context.getelcontext()); 392 393        // if there converter attribute, use to ask application 394        // instance converter identifer. 395        converter c = getconverter(); 396 397        if (c == null) { 398            // if value null , no converter attribute specified, 399            // return null (null has meaning view parameters; means remove it). 400            if (currentvalue == null) { 401                return null; 402            } 403            // not "by-type" converters strings 404            if (currentvalue instanceof string) { 405                return (string) currentvalue; 406            } 407 408            // if converter attribute set, try acquire converter 409            // using class type. 410 411            class convertertype = currentvalue.getclass(); 412            c = context.getapplication().createconverter(convertertype); 413 414            // if there no default converter available identifier, 415            // assume model type string. 416            if (c == null) { 417                return currentvalue.tostring(); 418            } 419        } 420 421        return c.getasstring(context, this, currentvalue); 422    } 

this method called every uiviewparameter (the ui component behind <f:viewparam>) during building query string includeviewparams=true. see in source calls converter regardless of whether currentvalue null or not. in other words, if model value null, still calls converter it.

as per javadoc of converter#getasstring() converters specification required return zero-length string if value null:

getasstring

...

returns: zero-length string if value null, otherwise result of conversion

so, converters supposed never return null on getasstring(). return empty string then. in case of view parameters in query string, highly undesirable. difference between empty string value , complete absence in query string significant.

i've reported mojarra guys issue 3288. should fix problem follows:

391        object currentvalue = ve.getvalue(context.getelcontext()); 392 393        if (currentvalue == null) { 394            return null; 395        } 

in meanwhile, i've committed solution omnifaces. <o:viewparam> has been extended fix. it's available per today's 1.8 snapshot.

<f:metadata>     <o:viewparam name="id" value="#{testmanagedbean.id}" converter="javax.faces.long"/> </f:metadata> 

update: decided not fix it. in case, there's omnifaces.


Comments

Popular posts from this blog

how to proxy from https to http with lighttpd -

android - Automated my builds -

python - Flask migration error -