I think it should be implemented in the core, not in individual components.

If someone is using a non-String value for a UIInput, it is a good bet
that there is a converter available to convert that value from
non-String to String and back.
This is why I think we should add an additional step of trying to use
an existing converter if one exists before defaulting to the no-arg
constructor value.
t:inputCalendar is a composite component, so I am not 100% sure if the
same solution will solve that issue, but the same general approach
makes sense.
Even if it doesn't solve the bridging problem, I am guessing that
there is still a serialization problem for those components.

I think the change should eventually be made in the spec, but we can
enable it with a custom parameter at first.

On Thu, Oct 4, 2012 at 11:43 PM, Leonardo Uribe <[email protected]> wrote:
> Hi
>
> I feel like a 'deja vu' with this problem. In tomahawk 1.1.10, it was
> introduced
> an interface to deal with a similar problem for t:inputCalendar and 
> t:inputDate
> called DateBusinessConverter. The code looks like this:
>
> /**
>  * Provide a bridge between the java.util.Date instance used by a component
>  * that receive date/time values and the "business" value used to represent
>  * the value.
>  *
>  * @since 1.1.10
>  * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
>  * @version $Revision: 691856 $ $Date: 2008-09-03 21:40:30 -0500 (mié,
> 03 sep 2008) $
>  */
> public interface DateBusinessConverter
> {
>     /**
>      * Convert the java.util.Date instance calculated from submittedValue,
>      * so the resulting object will be used later as the converted value
>      * and validation.
>      *
>      * @param context
>      * @param component
>      * @param value
>      * @return
>      */
>     public Object getBusinessValue(FacesContext context,
>                        UIComponent component,
>                        java.util.Date value);
>
>     /**
>      * Used to retrieve the value stored in the business bean and convert
>      * it in a representation that the component (t:inputCalendar and
>      * t:inputDate for example)using this class can manipulate.
>      *
>      * @param context
>      * @param component
>      * @param value
>      * @return
>      */
>     public java.util.Date getDateValue(FacesContext context,
>                        UIComponent component,
>                        Object value);
> }
>
> In summary, this interface provides a "bridge" between the value to be
> stored in the component (java.util.Date) and the value used in the bean.
> In this case t:inputCalendar understands only java.util.Date instances
> through CalendarDateTimeConverter, but with this we can have any
> non serializable and non stateholder instance on the beans.
>
> I know the intention of DateBusinessConverter is different to what
> is mentioned here, but the concept behind it is still valid. The idea was
> add some application scope object in tomahawk to deal with known
> date types (joda Datetime and others), but that would require an
> alternate faces-context.xml (tomahawk-context.xml).
>
> Something we can do is use the existing <faces-config-extension> to
> do something similar to what is proposed here and update the
> standard components to deal with this. Recently, I added a custom
> config param there, see:
>
> https://issues.apache.org/jira/browse/MYFACES-3612
>
> Is it worth to do it? maybe. This looks like something that you can't
> really fix correctly without put it into myfaces core, but maybe something
> like this should be solved in the spec directly, because otherwise,
> component libraries outside myfaces cannot use it without break
> compatibility with the spec.
>
> regards,
>
> Leonardo Uribe
>
> 2012/9/25 Mike Kienenberger <[email protected]>:
>> I've never paid a lot of detail to the implementation of state saving
>> up to this point as it never concerned me beyond implementing it in my
>> own components.
>>
>> Now that I've upgraded from JSF 1.2 to 2.1, I have hit various state
>> saving exceptions.  Some were due to t:saveState, which I have since
>> gotten rid of (most of this project is session scoped, and t:saveState
>> was a left-over from the original request-scoped project).   Some were
>> due to trying to create deferred El evaluation in validators, and that
>> code was likewise replaced with more appropriate code.
>>
>> However, my latest issue is with a UIInput with a Money converter.
>> We have a special java class to represent Money amounts.
>>
>> <h:inputText value="#{page.amount}">
>>         <my:convertMoney/>
>>         <my:validatePositiveMoney/>
>>         <a4j:ajax execute="@this" event="blur"
>> listener="#{page.paymentAmountChanged}" render="totalsPanelId"/>
>> </h:inputText>
>>
>> This has worked for the most part, except when validation of an
>> unrelated input field on the same page fails.   Then attempting to
>> continue after that causes the following exception for clazz =
>> Money.class.  Note that Money isn't serializable.
>>
>>                 throw new RuntimeException("Could not restore
>> StateHolder of type " + clazz.getName()
>>                         + " (missing no-args constructor?)", e);
>>             }
>>
>> So I traced through the code, and determined that this is because we
>> are attempting to restore the "value" of the inputText, which is is of
>> type Money.
>>
>> I read section 7.7 for StateManager in the JSF 2.1 spec.
>>
>>         Validators, Converters, FacesListeners, and other objects attached to
>> a component. The manner in
>>         which these attached objects are saved is up to the component
>> implementation. For attached objects that may have
>>         state, the StateHolder interface (see Section 3.2.4 “StateHolder”) is
>> provided to allow these objects to preserve
>>         their own attributes and properties. If an attached object does not
>> implement StateHolder, but does implement
>>         Serializable, it is saved using standard serialization. Attached
>> objects that do not implement either
>>         StateHolder or Serializable must have a public, zero-arg constructor,
>> and will be restored only to their
>>         initial, default object state.
>>
>> Since this is implementation-specific, we have latitude here.  Why do
>> we not use the specified converter to create a string if the value
>> object implements neither StateHolder nor Serializable?   We know the
>> converter is going to produce reversible reference to the value object
>> -- it is essentially going to serialize it into a String for us, which
>> is likely to be far more useful than the initial, default object
>> state.
>>
>> It seems to me that we should be doing this for all value objects with
>> converters.
>>
>> I know we have to follow the spec otherwise I'd go a step further and
>> say we should throw an exception rather than create an initial,
>> default object state, since I'd rather know as soon as possible when a
>> situation like this turns up rather than trying to debug some
>> uniitialized object at some point down the road.  Maybe that's
>> something we can add a oam behavior parameter for.

Reply via email to