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.
