We just started to migrate an older jsf 1 project to jsf version 2.3 with new requirements. Currently I am working on pages that use viewparams. what would be the right way to silently ignore wrong parameter-types?
for example with this definition for page searchResults.xhtml:
<f:metadata>
<f:viewParam name="lastPrice"
value="#{ReportAgentBean.lastPrice}" converter="javax.faces.Double"/>
<f:viewParam name="currentPrice"
value="#{ReportAgentBean.currentPrice}" converter="javax.faces.Double"/>
<f:viewParam name="listPrice"
value="#{ReportAgentBean.listPrice}" converter="javax.faces.Double"/>
</f:metadata>
what would be the best approach to ignore invalid parameters or just handle them as null if someone fires a request like:
http://www.ourapp.com/reports/searchResults?lastPrice=undefined?currentPrice=INVALIDSTRING
which ideally would result in:
http://www.ourapp.com/reports/searchResults
thanks for any hint.
As far as I know, the default faces converters you use cannot accept/ignore invalid values passed to it and ignore them.
For this to work, you need to create your own custom converters, do the casting to the right type in there and if the casting is successful, return the cast value and if it fails, return some default.
This is what you'd normally do for more complex param/converter combinations where just the presence of an id would read a full complex object from somewhere
This whole concept is also used in the OmniFaces #Param annotation which might be an interesting solution to. They set the fields to null if conversion fails. See the demo on that page too.
Related
I often face the following problem. I have a JSF application and a facelet where I write EL expressions, like this:
<h:outputText value="#{myBean.foo}">
As long as myBean, as a variable, has a life long enough, there's no problem to evaluate myBean.foo at any given time, but if myBean is a variable that references some bean within a short period of time, when myBean.foo is evaluated it might be too late, so that JSF complains that myBean resolves to null. This is something well-known, but the problem is that it is not clear to me what to expect in different situations.
Concrete example n. 1: if you try the following with PrimeFaces OrderList:
<p:orderList value="#{bean.myValue}" var="item">
<p:column>
<p:commandLink action="#{bean.doSomething(item)}" />
</p:column>
</p:orderList>`
This is not going to work, because when doSomething is called, the item variable is no longer defined (although the object it references is still alive) and hence it's resolved to null. It's a known issue. However the same pattern works fine with <p:dataTable>, for instance. Anyway, I'm not interested right now in this specific problem, I just want to explain my doubt.
Concrete example n. 2: I have written a composite component with a backing bean. The backing bean extends UINamingContainer and uses its StateHelper to retain a model object. This composite allows to write child tags and I would like to write something like this:
<myns:myCc var="myVar">
<h:inputText value="#{myVar.foo}" />
</myns>
With "myVar" I want to give a name to the model object. To make this work, I tried to store the model object in the request map at the beginning of encodeChildren method and remove it afterwards: this works for rendering, but if I then process the input with a commandButton action, it does not work because when the action gets executed it says that myVar can't be resolved: in other words, it tries to resolve the entire expression too late. I then tried to "permanently" save the model object in the view scope map, but it doens't work either. However, if I change this to:
(assuming modelObject is the property field in the backing bean that stores my model object)
it works. So, it is not a problem in my model, but in the way I try to make the model object available to EL expressions for child tags.
Concrete example n. 3: I often use the <ui:param> tag to give beans a shorter name and to ease templating. For instance:
<ui:param name="bean" value="#{longNamedAndPageSpecificBean}" />
So that, in the remainder of the page I can just use #{bean.foo} instead of #{longNamedAndPageSpecificBean.foo}. This works fine even for actions passed to command buttons. However, if I pass a method expression like #{bean.myActionMethod} to a composite component attribute declared with method-signature, when this method expression is actually invoked I receive an error that bean resolves to null... The reason why it works in one case (with commandButton actions) and not in the other (with actions used by the composite component) is a big source of confusion for me.
I would appreciate if someone can help me to understand better this JSF aspect and suggest better approaches/workarounds with the aforementioned concrete examples.
Your question looks too large, but i could say that, during the build time only Session and request scoped values are avaiaible.
The same thing is true for the Execution phase.
Only the render phase should ensure the avaibility of temporal vars "myVar".
The best way to understand what its realy hapening is to debug because its depends on the component implementation
I have got some interesting issue for you. I am creating a composite component. I know, that I can use ui:param for storing value and reuse it. But what if I store to this variable some relative value (#{component.namingContainer.clientId}) and want to reuse it as a constant? It is difficult to explain - here you have my code:
<ui:param name="rdfaComp" value="#{component.namingContainer.clientId}"/>
This is in the beginning of the page - I want to store exactly this ID and then use nothing else by this variable. But later if I reuse it inside elements with own IDs, it is bad. It is interesting, what happens - JSF doesn't take the same value, but a relative one. It reads once more #{component.namingContainer.clientId}, not the fixed value.
How to solve this, could you help me, please? THanks a lot.
UPDATED
There is still one important condition: the variable rdfaComp have to be available immediately, because I reuse it in a Javascript function (on the same page). Like this:
<h:commandButton onclick="return selectText('#{rdfaComp}:editor', ...
I am afraid, it is necessarry to use relative ID chains like this: #{component.namingContainer.parent.namingContainer.parent.clientId} etd.
But it is really awful. Is there another solution?
The <ui:param> indeed merely creates an alias and the EL expression is still deferred and evaluated on every access in the very same context as where it's been referenced (and thus not where it's been declared! that explains your concrete problem). Besides, the <ui:param> is designed to be used on <ui:include>, <ui:composition> and <ui:decorate> only.
Use <c:set> instead. It's capable of immediately evaluating an EL expression and storing its result in either request, view, session or application scope via the scope attribute.
<c:set var="rdfaComp" value="#{component.namingContainer.clientId}" scope="request" />
Update: you actually wanted to get the client ID of the composite component itself, here's how you can get it:
<c:set var="rdfaComp" value="#{cc.clientId}" scope="request" />
It is solved - and I must apologise once more :-). I didn't describe correctly the issue - what I really wanted to do. I just wanted to work with the full client ID of the composite component. Finally I found a solution: #{cc.namingContainer.clientId}
Thanks anyway, your answers were very helpful!
El function cannot be found using within validator attribute, which is dependent on dynamic or repeated values?
Function 'el:min' not found
#{el:min(a + b, c)}
<f:validateLongRange maximum="#{el:min(foo.bar, 10)}"/>
Just printing out the value is working where it is not working in the validator.
The error message Function 'el:min' not found was so misleading.
The problem was never the construct but it was an underlying NullPointerException on the nested property.
Since in one case the value was depending on a different component selection it was updated via ajax and the default value was null. Since the default value was null this misleading exception was thrown.
The value was a nested property, so it was not catched within the el function
Solution: disable the validator on default
<o:validator validatorId="javax.faces.LongRange" maximum="#{el:min(foo.bar, 10)}"
disabled="#{foo eq null}"/>
This construct should work just fine. The problem is most likely the scope of the variables which you've there and the timing (i.e. when do you need them? when are they "behind the scenes" changed?).
You need to understand that taghandlers like <f:xxx> run during view build time (like JSTL <c:xxx>). So their attribtues are resolved during view build time and would be filled with bean's default values. Perhaps you're performing some business logic on them while submitting the form and expecting that they would be reflected into the taghandler attribute. But this is not true. They were already evaluated during view build time and won't re-evaluate the values during processing the form submit.
If this is indeed the case, then you've basically the same problem which is already outlined and answered with various possible solutions in this answer: How to set converter properties for each row of a datatable? Apart form homegrowing a Validator for this, you could use OmniFaces <o:validator> for this:
<o:validator validatorId="javax.faces.LongRange" maximum="#{el:min(a + b, c)}" />
I have upgraded from JSF 1.1 to JSF 2.0. Earlier I was using f:validateLongRange or f:validateDoubleRange and the validation worked fine. However, since I have migrated to JSF 2.0 the validation message precedes with client ID which looks something like below :
FormID:ClientID:0:ComponentID in my case, the message appears as
premiumCategory:j_idt368:0:tlNewLOS: Validation Error: Specified attribute
is not between the expected values of 1 and 999,999.
There is a Jira which talks about prefixing ClientID but I dont think its of any use to me.
I learnt from the blog Communication in JSF 2.0 these tag handlers do not work correctly in JSF 2.0 thus we should create custom validators using f:validator
I followed BalusC’s answer from here; The only difference was I did not get my max and min values from the bean, I specified them in the xhtml,it still printed the validation message as stated above.
While debugging I realised that the client ID is generated as FormID:ClientID:0:ComponentID and is stored in the UIComponent instance which gets passed to the MessageFactory.getMessage method.
The same blog which I mentioned before has a topic in it saying "Ajax rendering of content outside form" which I thought would have a solution to my issue, but again no luck.
Now I have my own custom validator class which extends to DoubleRangeValidator and overrides validate method. I get the desired message. However, I am not convinced that writing a custom validator for each f:validatorXXXX component is the solution.
I am still on my learning curve, can anyone explain me why and where MessageFactory.getMessage binds these IDs to to the faces message?
Please advise,
Dakshata Gulkhobare
The label is overrideable by setting the label attribute on the input component of interest.
<h:inputText ... label="Your label" />
This way the validation message will be formatted as follows:
Your label: Validation Error: Specified attribute
is not between the expected values of 1 and 999,999
Otherwise it will indeed default to the component's client ID.
If you happen to use <h:outputLabel> already and would like to use exactly its value, but don't want to duplicate it into the label attribute of every single input component, then you may find OmniFaces <o:outputLabel> helpful.
I've been trying to solve this, and have been getting stuck, so I thought I'd ask.
Imagine two ActionBeans, A and B.
A.jsp has this section in it:
...
<jsp:include page="/B.action">
<jsp:param name="ponies" value="on"/>
</jsp:include>
<jsp:include page="/B.action">
<jsp:param name="ponies" value="off"/>
</jsp:include>
...
Take it as read that the B ActionBean does some terribly interesting stuff depending on whether the "ponies" parameter is set to either on or off.
The parameter string "ponies=on" is visible when you debug into the request, but it's not what's getting bound into the B ActionBean. Instead what's getting bound are the parameters to the original A.action.
Is there some way of getting the behaviour I want, or have I missed something fundamental?
So are you saying that in each case ${ponies} on your JSP page prints out "on"?
Because it sounds like you are confusing JSP parameters with Stripes action beans. Setting a JSP parameter simply sets a parameter on that JSP page, that you can reference as shown above, it doesn't actually set anything on the stripes action bean.
The reason that this wasn't working was because of massaging done by our implementation of HttpServletRequest.
It works fine with the "normal" implementation.