I am trying to do some "custom lightweight" JSF component binding. In my bean (controlling some JSF page) i'm declaring a HahsMap where keys ranging over my h:inputText ids (appearing in the page) map these ids to custom HInputText<T> objects (T in the example given below is Long). Then i am using HInputText<T> objects to hold a subset of corresponding h:inputText attributes : value supposed to be of type T, rendered, required, etc. In this direction fields from the HInputText<T> objects give values to the h:inputText attributes.

My problem is that when using such an h:inputText inside a h:form, JSF validation does not take place : i can type alphanumeric chars in the h:inputText (supposed to hold a Long value) and my form submits without showing any errors. Note that required and rendered attributes are managed correctly (since required is set to true, i have an error when i leave the h:inputText field empty) and that when i try to display back the value of the h:inputText in the page using some h:outputText the alphanumeric chars are displayed.

Is there some trick to make JSF validation work without having to explicitly define a custom Validator for each h:inputText?

HInputText.class:

public class HInputText<T>
{
    private String id;
    private boolean rendered;
    private boolean required;
    private T value;
    private Class<T> myClass;

    // getters and setters for all fields

    public HInputText(Class<T> myClass, String id)
    {
        this.myClass = myClass;
        this.id = id;
        this.rendered = true;
        this.required = true;
    }
}

Code snippet from my Managed Bean :

@ManagedBean(name="saisieController")
@SessionScoped
public class SaisieController
{
    ...
    private HashMap<String,HInputText<Long>> htagLongInputTexts;

    public HashMap<String, HInputText<Long>> getHtagLongInputTexts()
    {
        return htagLongInputTexts;
    }

    public void setHtagLongInputTexts(HashMap<String, HInputText<Long>> hLongInputTexts)
    {
        this.htagLongInputTexts = hLongInputTexts;
    }

    public void addHtagLongInputText(HInputText<Long> hLongInputText)
    {
        getHtagLongInputTexts().put(hLongInputText.getId(), hLongInputText);
    }

    public HInputText<Long> getHtagLongInputText(String hLongInputTextId)
    {
        return(getHtagLongInputTexts().get(hLongInputTextId));
    }



    @PostConstruct
    public void init()
    {
        setHtagLongInputTexts(new HashMap<String, HInputText<Long>>());
        addHtagLongInputText(new HInputText<Long>(Long.class, "HIT_LongTestHIT"));
    }

    public String doNothing()
    {
        return null;
    }
}

and finally a snippet from my jsf page:

<h:form>
    <h:inputText
        id = "HIT_LongTestHIT"
        value = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].value}"
        rendered = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].rendered}"
        required = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].required}"
    />
    <h:message for = "HIT_LongTestHIT" styleClass = "error-text" />
    <h:commandButton value = "submit" action = "#{saisieController.doNothing()}" />
    <h:outputText value = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].value}" />
</h:form>
1

There are 1 best solutions below

1
On BEST ANSWER

Is there some trick to make JSF validation work without having to explicitly define a custom Validator for each h:inputText?

No, that's not possible. Due to type erasure the generic type information is not available during runtime. JSF/EL has no idea that T is actually a Long, let alone that there's actually some T. You really need to explicitly specify a converter which is in this particular example the LongConverter with a converter ID of javax.faces.Long.

<h:inputText ... converter="javax.faces.Long">

or, dynamically so you want

<h:inputText ...>
    <f:converter converterId="#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].converterId}" />
</h:inputText>

You can find an overview of all available standard JSF converters in the javax.faces.convert package summary. You can find out their converter IDs by navigating to the Constant field values link on the public constant CONVERTER_ID.