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

Leonardo Uribe lu4242 at gmail.com
Thu Sep 23 14:31:28 EDT 2010


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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/jsr-314-open-mirror/attachments/20100923/02e69392/attachment-0002.html 


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