Search code examples
jsfuicomponentsfacescontext

When should I use UIComponent#popComponentFromEL(FacesContext context)?


I'm working on an existing JSF component where the encodeEnd method ends with:

// popComponentFromEL(context);

The Javadoc for UIComponent#popComponentFromEL(FacesContext context) tells me:

Pop the current UIComponent from the FacesContext attributes map so that the previous UIComponent, if any, becomes the current component.

When and why would you need or want that?

I've found that none of the other components in the same library are using it.


Solution

  • That's the counterpart of pushComponentToEL() whose Javadoc explains this more elaborately.

    pushComponentToEL

    public final void pushComponentToEL(FacesContext context, UIComponent component)

    Push the current UIComponent this to the FacesContext attribute map using the key CURRENT_COMPONENT saving the previous UIComponent associated with CURRENT_COMPONENT for a subsequent call to popComponentFromEL(javax.faces.context.FacesContext).

    This method and popComponentFromEL() form the basis for the contract that enables the EL Expression "#{component}" to resolve to the "current" component that is being processed in the lifecycle. The requirements for when pushComponentToEL() and popComponentFromEL() must be called are specified as needed in the javadoc for this class. After pushComponentToEL() returns, a call to getCurrentComponent(javax.faces.context.FacesContext) must return this UIComponent instance until popComponentFromEL() is called, after which point the previous UIComponent instance will be returned from getCurrentComponent()

    Basically, this approach

    public void encodeXxx(FacesContext context) {
        try {
            pushComponentToEL(context, this);
    
            // ...
        }
        finally {
            popComponentFromEL(context);
        }
    }
    

    allows you during the // ... process to grab this component using #{component} in EL, or UIComponent#getCurrentComponent() in a managed bean.

    One of well known examples is this construct:

    <h:inputText ... styleClass="#{component.valid ? 'valid' : 'error'}" />
    

    where #{component.valid} basically refers UIInput#isValid().