Hi<br><br>This issue has been posted on spec issue tracker:<br><br> <a href="https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=888">https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=888</a><br>
<br>The current conversion model is not good enough on some cases when it <br>is required the submitted value be something different than String, or on<br>more complex components that requires to send information from multiple html <br>
"input" components.<br>This issue has been discussed earlier on myfaces list, as you can <br>see on the comments at the end of this mail:<br><br>To understand what's missing, I'll resume how the current conversion model works.<br>
This could be redundant, but the intention is expose the reasons about why it is<br>wanted to extend the current model in a understandable way.<br><br>Every component that is used as a input has at least one "value binding" to a bean. <br>
In UIInput, the user just set "value" property with an EL expression to <br>indicate that the value sent should be assigned to that expression.<br><br>Now suppose a form with this component that is submitted. The input component <br>
should first create the "submittedValue" from the information available on <br>request parameter map. This is done on UIComponent or Renderer decode() method.<br>Then, this value is converted to the type required by the "value binding", through<br>
Converter interface and later, if conversion fails by some reason, the information<br>stored on "submittedValue" will be used to render the component later.<br><br>Therefore, "submittedValue" must satisfy three conditions: <br>
<br> 1. It should contain all info sent by the component through request parameter map,<br> otherwise the renderer will not be able to render the component correctly.<br> 2. It should be on a way that can be converted to the type indicated by "value binding",<br>
that means the submittedValue type should be a public class, so the renderer can<br> instantiate it and conversion model can process it.<br> 3. The component should be responsible to define the type used by submitted value,<br>
according to its needs.<br><br>Now, let's take a look at the current Converter interface:<br><br>public interface Converter<br>{<br> /**<br> * used to map the submittedValue to the "value binding".<br>
*/<br> Object getAsObject(FacesContext context,<br> UIComponent component,<br> String value) throws ConverterException;<br><br> /**<br> * used to convert the "value binding" into a String to be used<br>
* on the renderer.<br> */<br> String getAsString(FacesContext context,<br> UIComponent component,<br> Object value) throws ConverterException;<br>}<br><br>Note that JSF provide some converters for the most common types, so the user can <br>
specify which converter use or let JSF decide which one fits best, using<br>the converters registered with "forClass" mapping. Yes, that's ok, but only for<br>components with only one "<input>". In that case, assume String as submitted<br>
value type looks better and keep things simple. <br><br>Things start to get confusing when you see the signature of UIInput.getSubmittedValue():<br><br>public Object getSubmittedValue()<br><br>Does the conversion model did not make the assumption that String is the only type to<br>
be used by submittedValue?<br><br>But this assumption fails when a more complex component is required. The typical<br>example is a component that handles date/time values. In that case, the date/time value<br>can be decomposed into its elements (year, month, day, hour, minutes ....).<br>
In this case, a component developer could want to send all that info into multiple<br>"<input>" parameters through request parameter map. So, to use the model proposed,<br>all that information should be used to encode a String, just to later decode it on<br>
the converter used to construct the "value binding" required, but later it will be<br>decoded/encoded by the renderer again to render the component. <br><br>The proposal to put into consideration is do the following modifications on jsf:<br>
<br>- Add a class called BusinessConverter (maybe you can find other name but for now let<br>it as is) :<br><br>public interface BusinessConverter<br>{<br> public Object getBusinessValue(FacesContext context,<br> UIComponent component,<br>
Object submittedValue);<br> <br> public Object getAsSubmittedValue(FacesContext context,<br> UIComponent component,<br> Object value);<br>}<br><br>Really is similar to Converter interface but does not force submittedValue to be String,<br>
instead it lets it open.<br><br>- Add the following methods to Application class :<br><br> public abstract void addBusinessConverter(Class<?> submittedClass,<br> Class<?> targetClass, <br>
String converterClass);<br><br> public abstract void addBusinessConverter(String businessConverterId, <br> String businessConverterClass);<br>
<br> public abstract Converter createBusinessConverter(Class<?> submittedClass, <br> Class<?> targetClass);<br><br> public abstract Converter createBusinessConverter(String businessConverterId);<br>
<br> public abstract Iterator<String> getBusinessConverterIds();<br><br> public abstract Iterator<Class<?>> getBusinessConverterTypes(Class<?> submittedClass);<br><br>Again, it is similar to converter methods on Application class, but in this case it takes<br>
into consideration the submittedClass. Therefore, a component that define as submittedClass <br>java.util.Date, could retrieve the converters that can handle this conversion. From some<br>point of view, the current Converter interface is a particular case when submittedClass is<br>
java.lang.String. <br><br>- Add the following methods to UIOutput class :<br><br> public BusinessConverter getBusinessConverter();<br> <br> public void setBusinessConverter(BusinessConverter converter);<br> <br>
/**<br> * Return the value type the submitted value will take on<br> * decode() method. In my opinion, allow just one submittedValueType is<br> * enough.<br> */<br> public Class<?> getSubmittedValueClass();<br>
<br>The idea is provide a way to configure business converter, just like Converter.<br>Note this implies change some stuff on UIInput too.<br><br>- Add an annotation @FacesBusinessConverter.<br><br>- Add a component f:businessConverter in the same way as f:converter.<br>
<br>I would like to put into consideration this idea. My personal opinion is this should be<br>included at the spec level for two reasons:<br><br>- It is clear there is a contradiction between UIInput.getSubmittedValue() and <br>
Converter interface.<br>- It could be good to have a common repository for business converters, and use JSF<br> annotations to register it. <br><br>I have some code I'm working but it is better to know if you think it is worth or <br>
not before continue. If it is necessary I can help with the implementation.<br><br>Suggestions are welcome<br><br>best regards,<br><br>Leonardo Uribe<br><br>Note: As an historical comment, currently, Trinidad has a workaround for handle <br>
handle "oracle types", from the binding layer, using an interfaces called <br>TypedConverter as you can see below:<br><br>package org.apache.myfaces.trinidadinternal.convert;<br><br>public interface TypeConverter<br>
{<br> /**<br> * converts the given Object into an instance of the <br> * targetType.<br> * @return an instance of the targetType.<br> */<br> Object convert(Object source, Class<?> targetType);<br>}<br><br>
The idea behind this interface is provide a way that trinidad can "understand"<br>specific types and include them when are resolved, but note this class is not<br>part of trinidad api. The reason is this is just an internal workaround. <br>
<br>COMMENTS FROM OTHER PEOPLE SUPPORTING THIS ISSUE:<br> <br>Martin Koci<br><br>MK>> maybe this is a stupid question but:<br>MK>><br>MK>> >From UIInput javadoc:<br>MK>><br>MK>> ... decoded value of this component, usually but >>>not necessarily a<br>
MK>> String<<<, must be stored - but not yet converted - using<br>MK>> setSubmittedValue() ....<br>MK>><br>MK>> from UIInput.getConvertedValue:<br>MK>><br>MK>> ... and the submitted value is a >>>String<<<, locate a Converter as<br>
MK>> follows<br>MK>><br>MK>> Question: why is Converter tied only to String? Whole specification<br>MK>> speaks about submitted value as of "raw representation of value from<br>MK>> client" but not necessarily String. And 3.3 Conversion Model: "This<br>
MK>> section describes the facilities provided by JavaServer Faces to support<br>MK>> type conversion between server-side Java objects and their (typically<br>MK>> String-based) representation in presentation markup."<br>
MK>> But Converter.getAsObject expects only String as this "raw<br>MK>> representation" and "typically String-based" formulation from spec now<br>MK>> means "always String-based".<br>
MK>> It seems to me that Converter introduces unnecessary dependency on<br>MK>> String-based representation - even ResponseWriter.write* accepts<br>MK>> java.lang.Object as value ....<br>MK>><br>MK>> What I try to do is JSF-based server view with custom NOT-string based<br>
MK>> protocol where "raw representations from client" can be java object like<br>MK>> Integer or more complex. Creating of:<br>MK>><br>MK>> interface Converter2 {<br>MK>> Object getAsObject(FacesContext,UIComponent,Object)<br>
MK>> Object getAsRepresentation(FacesContext,UIComponent,Object)<br>MK>> }<br>MK>><br>MK>> solves my problem but I must reprogram significant part of JSF api.<br> <br>Martin Marinschek<br><br>
MM>> MK>> So on JSF level conversion String <-> Object is unable to solve this<br>MM>> MK>> problem - I simply need Object <-> Object conversion which is not<br>MM>> MK>> supported yet.<br>
MM>> <br>MM>> Yes, this is true - this is obviously a spec problem.<br>MM>> <br>MM>> If the submitted value is an object, it should also be allowed to<br>MM>> convert it. A converter is more than just a string to object (and<br>
MM>> back) converter, it is an artefact which transforms information from<br>MM>> its representation for output (and this output could be anything, and<br>MM>> certainly doesn't have to be string based) to its representation which<br>
MM>> the business model (or also an artefact within JSF, like a validator)<br>MM>> understands.<br>MM>> <br>MM>> So I agree. This hasn't come up so far cause nobody uses non string<br>MM>> based output models for JSF.<br>
MM>> <br>MM>> Note that my notion of a business converter (discussed on this mailing<br>MM>> list a while ago) for converting between a business model<br>MM>> representation and a representation in a JSF artefact like the<br>
MM>> renderer (e.g. you use joda.Date in the business model, but the JSF<br>MM>> date picker renderer only understands the normal java date) is also<br>MM>> hinting in the direction that such an additional converter API would<br>
MM>> be necessary. I discussed this with the EG (and also Ed privately),<br>MM>> and there wasn't much interest for adding this.<br><br><br><br>