Affects Version/s: 1.1
Fix Version/s: None
Operating System: All
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
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,
String value) throws ConverterException;
- used to convert the "value binding" into a String to be used
- on the renderer.
String getAsString(FacesContext context,
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
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 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,
public Object getAsSubmittedValue(FacesContext context,
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,
public abstract void addBusinessConverter(String businessConverterId,
public abstract Converter createBusinessConverter(Class<?> submittedClass,
public abstract Converter createBusinessConverter(String businessConverterId);
public abstract Iterator<String> getBusinessConverterIds();
public abstract Iterator<Class<?>> getBusinessConverterTypes(Class<?>
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
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
- 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
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:
public interface TypeConverter
- converts the given Object into an instance of the
- @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:
MK>> maybe this is a stupid question but:
MK>> >From UIInput javadoc:
MK>> ... decoded value of this component, usually but >>>not necessarily a
MK>> String<<<, must be stored - but not yet converted - using
MK>> setSubmittedValue() ....
MK>> from UIInput.getConvertedValue:
MK>> ... and the submitted value is a >>>String<<<, locate a Converter as
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>> 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>> interface Converter2
MK>> solves my problem but I must reprogram significant part of JSF api.
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>> Yes, this is true - this is obviously a spec problem.
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>> So I agree. This hasn't come up so far cause nobody uses non string
MM>> based output models for JSF.
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.