javaserverfaces-spec-public
  1. javaserverfaces-spec-public
  2. JAVASERVERFACES_SPEC_PUBLIC-888

UIInput.submittedValue returns Object, but Converter suggest only String is allowed

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 1.1
    • Fix Version/s: None
    • Component/s: Components/Renderers
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      888
    • Status Whiteboard:
      Hide

      size_medium importance_medium

      Show
      size_medium importance_medium

      Description

      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.

        Activity

        Hide
        Ed Burns added a comment -

        Target for 2.2.

        Show
        Ed Burns added a comment - Target for 2.2.
        Hide
        rogerk added a comment -

        triage

        Show
        rogerk added a comment - triage
        Hide
        rogerk added a comment -

        triage

        Show
        rogerk added a comment - triage
        Hide
        Ed Burns added a comment -

        Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.

        Show
        Ed Burns added a comment - Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.

          People

          • Assignee:
            Unassigned
            Reporter:
            lu4242
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: