[jsr-314-open-mirror] [jsr-314-open] Enhance conversion model is required because UIInput.submittedValue returns Object, but Converter suggest only String is allowed

Martin Marinschek mmarinschek at apache.org
Fri Oct 15 03:52:33 EDT 2010


Hi guys,

this is maybe not a high priority item, but we might want to think
about this for 2.2. All this abstraction that is built into JSF -
renderer can emit anything, not only HTML is really only useful if it
can be used properly - this is essentially preventing some people from
using JSF for non-string based input/output.

best regards,

Martin

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



-- 

http://www.irian.at

Your JSF powerhouse -
JSF Consulting, Development and
Courses in English and German

Professional Support for Apache MyFaces




More information about the jsr-314-open-mirror mailing list