1

JSF Converter seems like is invoked before any other managed bean on the xhtml page. It is even created with rendered=false on the h:selectOneMenu component.

I have created 3 managed beans to test initialization sequence and managed beans are initialized in sequence they appear in xhtml, but before any of them JSF converter is created despite being last.

Form

<h:form>
    <h:inputText value="#{creationTime1.string1}"/>
    <h:inputText value="#{creationTime3.string3}"/>
    <h:inputText value="#{creationTime2.string2}"/>
    <h:selectOneMenu value="#{creationTime1.competitor}" rendered="false" converter="#{testConverter}" >
        <f:selectItem itemValue="#{null}" itemLabel="#{msg.none}" />
        <f:selectItems value="#{creationTime1.competitorList}" var="competitor" itemValue="#{competitor}"
                       itemLabel="#{competitor.idCompetitor}"/>
    </h:selectOneMenu>
    <h:commandButton value="GO" action="#{creationTime1.submit}"/>
</h:form>

Converter

@Named(value = "testConverter")
@ViewScoped
public class TestConverter implements Converter, Serializable {

    @PostConstruct
    private void init() {
        System.out.println(System.currentTimeMillis() +  " || TestConverter init");
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        ...
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        ...
    }
}

Managed Beans (all the same with different names)

@Named(value = "creationTime2")
@ViewScoped
public class CreationTime2 implements Serializable {

    private String string2;

    public String getString2() {
        System.out.println("getter srting2");
        return string2;
    }

    public void setString2(String string2) {
        this.string2 = string2;
    }

    @PostConstruct
    private void init() {
        System.out.println(System.currentTimeMillis() +  " || CreationTime2 init");
    }
}

Results on page visit

Info:   START PHASE RESTORE_VIEW 1
Info:   END PHASE RESTORE_VIEW 1
Info:   START PHASE RENDER_RESPONSE 6
Info:   1451147920374 || TestConverter init
Info:   1451147920401 || CreationTime1 init
Info:   getter string1
Info:   1451147920407 || CreationTime3 init
Info:   getter string3
Info:   1451147920414 || CreationTime2 init
Info:   getter string2
Info:   END PHASE RENDER_RESPONSE 6

I also tried with @FacesConverter instead of CDI bean and the results are the same.

  1. Why is converter invoked before any other bean?
  2. Why is converter created with rendered=false? Shouldn't it just pass h:celectOneMenu like it does not exist and don't create itself?
  3. Can I somehow make converter create itself after these 3 beans (in order it appears on the xhtml page)?

Using

  • Mojarra 2.2.7
  • GlassFish 4.1
Geinmachi
  • 1,251
  • 1
  • 8
  • 20
  • 1. Since Phase 3 validations requires converters be created. ***By default, during the Process Validators phase of the request processing lifecycle, the submitted value will be converted to a typesafe object, and, if validation succeeds, stored as a local value using setValue(). However, if the immediate property is set to true, this processing will occur instead at the end of the Apply Request Values phase.*** -- https://javaserverfaces.java.net/nonav/docs/2.2/javadocs/javax/faces/component/UIInput.html – Mahendran Ayyarsamy Kandiar Dec 26 '15 at 20:13
  • 2. rendered="false" prevents it from rendering the HTML output, but it doesn't prevent it from ending up in JSF component tree and being eligible for state saving. - The great @BalusC – Mahendran Ayyarsamy Kandiar Dec 26 '15 at 20:16
  • 3. Impossible - the very ordinary me – Mahendran Ayyarsamy Kandiar Dec 26 '15 at 20:17

1 Answers1

5

Why is converter invoked before any other bean?

The converter isn't exactly "invoked" here, i.e. neither getAsObject() nor getAsString() is invoked at that moment. It's just instantiated during building the view and then assigned as a property of the parent ValueHolder component. JSF does that for every converter, validator and (ajax)behavior declared on the component.

The converter actually being a managed bean doesn't make difference in this. This is just a trick in order to be able to inject a.o. an EJB in it. JSF inspects if the value is a literal string or an EL expression. If a literal string, then it's treated as converter ID to create the converter instance, else if the EL expression returns a concrete Converter instance, then it's directly used. Or if there's nothing, then JSF will create the converter by target class matching the value type, if any.


Why is converter created with rendered=false?

Because the rendered attribute is only evaluated during view render time, not during view build time.


Can I somehow make converter create itself after these 3 beans (in order it appears on the xhtml page)?

No, but if the "unnecessary" instantiation of the converter is your concern, then you could use JSTL to conditionally add the converter.

<h:selectOneMenu ... rendered="#{bean.condition}">
    <c:if test="#{bean.condition}"><f:converter binding="#{testConverter}" /></c:if>
    ...
</h:selectOneMenu>

You only need to keep in mind that <x:someComponent rendered> and <c:if test> aren't evaluated at the same moment. The <c:if test> is evaluated during view build time and the <x:someComponent rendered> is evaluated during view render time. So if the condition happens to change between those moments for some reason, then you basically need to rebuild the view (i.e. explicitly navigate to the same view instead of returning void/null). This may get nasty if the condition is tied to a view scoped bean property as the bean gets recreated. You'd basically need to retain the condition during its @PostConstruct.

Nonetheless, the converter (and validator and behavior) being instantiated anyway should be your least concern. If there's however a performance hit as to instantiation, or a technical problem as to instantiation ordering, then you'd best look for a different solution, depending on the concrete functional requirement.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555