The only problem with this approach is I already have a domain model that i
have written a custom resolver for, so I can bind directly to it. Going this
approach I would have to copy the value from the backing bean to my domain
model. I don't want to have to maintain a copy like that.
Scott O'Bryan wrote:
>
> :) That was going to be my suggestion.
>
> Andrew Robinson wrote:
>> Another solution you could consider, is doing the
>> conversion/validation in the backing bean instead of in the component,
>> it is messy, but possibly less messy than what I told you. It is more
>> work though.
>>
>> public class Bean {
>> private Integer intValue;
>> private String submittedIntValue;
>> // standard get/set properties here for intValue
>>
>> public String getSubmittedValue() {
>> if (submittedIntValue == null) { return intValue.toString(); }
>> return submittedIntValue();
>> }
>> public void setSubmittedValue(String value) {
>> try {
>> submittedIntValue = value;
>> if (value == null || value.length() == 0) { intValue = null; }
>> intValue = Integer.parseInt(value);
>> submittedIntValue = null;
>> } catch (NumberFormatException ex) { }
>> }
>> ...
>>
>> <h:inputText value="#{bean.submittedIntValue}" />
>>
>> Since the backing bean takes any string, you will never get conversion
>> or validation errors and update model will always take place. Then
>> since the inputText is valid, there is no submitted value and no local
>> value, and thus it would get the value from the value binding. Thus it
>> is the bean that is doing the work of the conversion and validation.
>>
>> -Andrew
>>
>> On 7/6/07, Toppac <[EMAIL PROTECTED]> wrote:
>>>
>>> Unfortunately I was afraid this may be the answer. I knew from
>>> looking at the
>>> code that it may require heavy modfications and a departure from the JSF
>>> spec. Hopefully I can get the requirements changed. Thanks.
>>>
>>>
>>> Andrew Robinson-5 wrote:
>>> >
>>> > The problem is really that you are going against the UIInput part of
>>> > the JSF specification. By definition, during the processValidators
>>> > method, if a UIInput component is found to be invalid, then
>>> > renderResponse is called on the current facescontext.
>>> >
>>> > Since you want control of the component's submitted value, perhaps
>>> > your best bet is component binding or a phase listener, or you could
>>> > even queue custom events.
>>> >
>>> > I can't see an easy way for you do this without a significant hack
>>> > though. Especially, trying to reset submitted values will get
>>> > especially ugly for components in iterating parents (data table, data
>>> > list, tree2, etc.).
>>> >
>>> > The easiest hack I would say is to create a phase listener that
>>> > listens for the before and after validation phase. In that phase
>>> > listener, replace the faces context. Crude example:
>>> >
>>> > public void beforePhase(PhaseEvent evt) {
>>> > new CustomFacesContext(evt.getFacesContext());
>>> > }
>>> > public void afterPhase(PhaseEvent evt) {
>>> > ((CustomFacesContext)evt.getFacesContext()).unwrap();
>>> > }
>>> > private class CustomFacesContext extends FacesContextWrapper
>>> > {
>>> > private FacesContext wrapped;
>>> > public CustomFacesContext(FacesContext orig) {
>>> > super(orig);
>>> > wrapped = orig;
>>> > FacesContext.setCurrentInstance(this);
>>> > }
>>> >
>>> > public void renderResponse() { /* swallow */ }
>>> >
>>> > public void unwrap() { wrapped.setFacesContext(wrapped); }
>>> > }
>>> >
>>> >
>>> > Now despite invalid UIInput components, the phases will continue. I
>>> > haven't thought through all the ramifications though. You may get some
>>> > ugly side-effects from doing this.
>>> >
>>> > -Andrew
>>> >
>>> > On 7/6/07, Toppac <[EMAIL PROTECTED]> wrote:
>>> >>
>>> >> I am using a custom converter to return null so I can bypass these
>>> >> conversion
>>> >> errors during submission. What I want to happen is that even when I
>>> >> bypass
>>> >> these and have my converter return null, I want to have a way to
>>> inject
>>> >> the
>>> >> submitted value back in during renderResponse. This does not
>>> appear to
>>> >> work
>>> >> with MyFaces out of the box. There is not hook to the converter
>>> for some
>>> >> reason and the local value of the component is null. That is the
>>> problem
>>> >> I
>>> >> am trying to solve.
>>> >>
>>> >>
>>> >>
>>> >> Andrew Robinson-5 wrote:
>>> >> >
>>> >> > Just about all components check their member values before they
>>> check
>>> >> > the value bindings. UIOutput is no different. So if either the
>>> >> > submittedValue or local value is set, your ValueBinding expression
>>> >> > will not be called. The local value should be converted before
>>> being
>>> >> > rendered however.
>>> >> >
>>> >> > If you don't want to throw a conversion error when the user enters
>>> >> > "abc", then write a custom converter that doesn't throw an
>>> error. You
>>> >> > could turn "abc" in to null or 0, based on your requirements for
>>> >> > example.
>>> >> >
>>> >> > If you use custom validators and custom converters, you can make
>>> it so
>>> >> > that exceptions are never thrown from converting and validation.
>>> >> >
>>> >> > Out of curiosity, why do you want to update the model when there is
>>> >> > invalid data?
>>> >> >
>>> >> > If you are only wanting to submit one value and don't care if other
>>> >> > values are invalid, then I would suggest using the subForm
>>> component
>>> >> > from the sandbox or the a4j:region if you are using ajax4jsf.
>>> >> >
>>> >> > -Andrew
>>> >> >
>>> >> > On 7/6/07, Toppac <[EMAIL PROTECTED]> wrote:
>>> >> >>
>>> >> >> Ok I follow. There a couple of problems here though. let's say my
>>> >> >> converter
>>> >> >> is for java.lang.Integer and the submitted value from the POST is
>>> >> "abc".
>>> >> >> I
>>> >> >> can't use the default converter since it will throw an
>>> exception and
>>> >> try
>>> >> >> to
>>> >> >> skip directly to renderResponse, not what i want to happen.
>>> Right now
>>> >> my
>>> >> >> converter is just returning null at this point and caches the
>>> >> submitted
>>> >> >> value. The rest of the lifecycle goes through and during update
>>> model
>>> >> the
>>> >> >> submitted value is set to null since updateModel succeeds.
>>> >> >>
>>> >> >> During renderResponse it appears that it tries to get the value
>>> from
>>> >> the
>>> >> >> component first, and if the component does not have a value it
>>> tries
>>> >> to
>>> >> >> get
>>> >> >> it from evaluating the value binding (see UiOutput.getValue).
>>> In this
>>> >> >> case
>>> >> >> they are both null, which is expected. But it never tries to
>>> call my
>>> >> >> converter which would restore the cached submitted valued.
>>> >> >>
>>> >> >>
>>> >> >>
>>> >> >>
>>> >> >>
>>> >> >> Andrew Robinson-5 wrote:
>>> >> >> >
>>> >> >> > Typical UIInput behavior:
>>> >> >> >
>>> >> >> > Decode phase ->
>>> >> >> > Is there a value in the POST values with the current component's
>>> >> client
>>> >> >> > ID?
>>> >> >> > If so, set the submitted value to that
>>> >> >> >
>>> >> >> > Validate phase ->
>>> >> >> > If there is a submitted value, get the converter
>>> >> >> > If there is a converter, convert the submitted value using
>>> >> getAsObject
>>> >> >> > Validate the submitted value
>>> >> >> > If valid, set the local value
>>> >> >> >
>>> >> >> > Update phase ->
>>> >> >> > If there is a local value, update the value binding property
>>> >> >> >
>>> >> >> > Render phase ->
>>> >> >> > If there is a submitted value, render that
>>> >> >> > Otherwise, get the value from the component
>>> >> >> > If there is a converter, convert the value using getAsString
>>> >> >> > Render the value
>>> >> >> >
>>> >> >> > So as you can see, as long as a UIInput control has a submitted
>>> >> value,
>>> >> >> > it will never render the value from the value attribute of the
>>> >> >> > component. Typically submitted values are only cleared in the
>>> >> validate
>>> >> >> > method of UIInput (if the converted value is valid)
>>> >> >> >
>>> >> >> > On 7/6/07, Toppac <[EMAIL PROTECTED]> wrote:
>>> >> >> >>
>>> >> >> >> I don't think I follow what you are saying exactly. Can you
>>> >> elaborate?
>>> >> >> >>
>>> >> >> >>
>>> >> >> >>
>>> >> >> >> Andrew Robinson-5 wrote:
>>> >> >> >> >
>>> >> >> >> > Converter will only be called if there is no submitted value.
>>> >> >> >> > Submitted values are already technically converted as they
>>> came
>>> >> from
>>> >> >> >> > the client, so there is no need to use the converter.
>>> >> >> >> >
>>> >> >> >> > On 7/6/07, Toppac <[EMAIL PROTECTED]> wrote:
>>> >> >> >> >>
>>> >> >> >> >> Just for a small background. I am trying to find a way to
>>> fail
>>> >> >> >> validation
>>> >> >> >> >> and/or conversion without dumping out of the JSF
>>> lifecycle to
>>> >> >> render
>>> >> >> >> >> response. I'd like to inject a custom converter that when it
>>> >> fails
>>> >> >> to
>>> >> >> >> >> convert it saves the submitted value to a session scoped
>>> Map and
>>> >> >> then
>>> >> >> >> >> during
>>> >> >> >> >> render response, when it tries to render the component that
>>> >> failed
>>> >> >> >> >> conversion, the getAsString method would see that the
>>> incoming
>>> >> >> value
>>> >> >> >> is
>>> >> >> >> >> null
>>> >> >> >> >> and would go to the session map to grab the last submitted
>>> >> value.
>>> >> >> >> >>
>>> >> >> >> >> Sounds easy enough and should work. But when I tried it, it
>>> >> appears
>>> >> >> >> that
>>> >> >> >> >> during render response, if the value on the domain model
>>> is null
>>> >> >> (or
>>> >> >> >> if
>>> >> >> >> >> the
>>> >> >> >> >> component value is null, not sure) it does not call the
>>> >> >> >> >> converter.getAsString method. I am not sure why. If
>>> someone can
>>> >> >> tell
>>> >> >> >> me
>>> >> >> >> >> why
>>> >> >> >> >> and where it makes this decision that would be great. If
>>> this is
>>> >> a
>>> >> >> bug
>>> >> >> >> >> then
>>> >> >> >> >> great also. But if it is not a bug then can anyone
>>> suggest a way
>>> >> to
>>> >> >> do
>>> >> >> >> >> what
>>> >> >> >> >> I am trying to do?
>>> >> >> >> >> --
>>> >> >> >> >> View this message in context:
>>> >> >> >> >>
>>> >> >> >>
>>> >> >>
>>> >>
>>> http://www.nabble.com/Converter.getAsString-not-called--tf4038047.html#a11472287
>>>
>>>
>>> >> >> >> >> Sent from the MyFaces - Users mailing list archive at
>>> >> Nabble.com.
>>> >> >> >> >>
>>> >> >> >> >>
>>> >> >> >> >
>>> >> >> >> >
>>> >> >> >>
>>> >> >> >> --
>>> >> >> >> View this message in context:
>>> >> >> >>
>>> >> >>
>>> >>
>>> http://www.nabble.com/Converter.getAsString-not-called--tf4038047.html#a11472464
>>>
>>>
>>> >> >> >> Sent from the MyFaces - Users mailing list archive at
>>> Nabble.com.
>>> >> >> >>
>>> >> >> >>
>>> >> >> >
>>> >> >> >
>>> >> >>
>>> >> >> --
>>> >> >> View this message in context:
>>> >> >>
>>> >>
>>> http://www.nabble.com/Converter.getAsString-not-called--tf4038047.html#a11472718
>>>
>>>
>>> >> >> Sent from the MyFaces - Users mailing list archive at Nabble.com.
>>> >> >>
>>> >> >>
>>> >> >
>>> >> >
>>> >>
>>> >> --
>>> >> View this message in context:
>>> >>
>>> http://www.nabble.com/Converter.getAsString-not-called--tf4038047.html#a11473052
>>>
>>>
>>> >> Sent from the MyFaces - Users mailing list archive at Nabble.com.
>>> >>
>>> >>
>>> >
>>> >
>>>
>>> --
>>> View this message in context:
>>> http://www.nabble.com/Converter.getAsString-not-called--tf4038047.html#a11473455
>>>
>>>
>>> Sent from the MyFaces - Users mailing list archive at Nabble.com.
>>>
>>>
>>
>
>
>
--
View this message in context:
http://www.nabble.com/Converter.getAsString-not-called--tf4038047.html#a11509233
Sent from the MyFaces - Users mailing list archive at Nabble.com.