Search code examples
springjsfprimefacesjsf-2.2remotecommand

Supplying parameters through p:remoteCommand to a Spring bean


The following XHTML sets a selected value in <p:selectOneMenu> to a request scoped bean through <p:remoteCommand>.

<h:form id="languageForm" prependId="true">

    <pe:blockUI target=":body" widgetVar="blockBodyUIWidget">
        <h:panelGrid columns="2">
            <h:graphicImage library="default" name="images/ajax-loader1.gif" class="block-ui-image"/>
            <h:outputText value="#{messages['blockui.panel.message']}" class="block-ui-text"/>
        </h:panelGrid>
    </pe:blockUI>

    <p:selectOneMenu id="languages" value="#{localeBean.language}" onchange="changeLanguage([{name:'language', value:this.value}]);">
        <f:selectItem itemValue="en" itemLabel="#{messages['languages.english']}" />
        <f:selectItem itemValue="hi" itemLabel="#{messages['languages.hindi']}" />
    </p:selectOneMenu>

    <p:remoteCommand name="changeLanguage" process="@this" update="@none" onstart="PF('blockBodyUIWidget').block();" oncomplete="PF('blockBodyUIWidget').unblock();" action="#{intermediateLocaleBean.localeAction}"/>
</h:form>

The corresponding JSF managed bean:

@ManagedBean
@RequestScoped
public final class IntermediateLocaleBean
{
    @ManagedProperty("#{param.language}")
    private String language;
    @ManagedProperty("#{localeBean}")
    private LocaleBean localeBean;  //Injecting another session scoped bean here.

    public IntermediateLocaleBean() {}

    public void setLanguage(String language) {
        this.language = language;
    }

    public void setLocaleBean(LocaleBean localeBean) {
        this.localeBean = localeBean;
    }

    public String localeAction()
    {
        localeBean.setLocale(language.equals("hi")?new Locale(language, "IN"):new Locale(language));
        return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true";
    }
}

The language property is initialized to the selected language in <p:selectOneMenu>. This is all done as it is a JSF managed bean.


What if, the bean is maintained by Spring like as follows?

@Controller
@Scope("request")
public final class IntermediateLocaleBean
{
    //Do something to initialize the property - language.
    //@ManagedProperty would not work as this bean is managed by Spring.
    //It is not initialized to the selected language in <p:selectOneMenu>.
    //It is null.

    private String language;

    //The session scoped bean is injected using the @Autowired annotation as follows.

    @Autowired
    private final transient LocaleBean localeBean=null;

    public IntermediateLocaleBean() {}

    public void setLanguage(String language) {
        this.language = language;
    }

    public String localeAction()
    {
        localeBean.setLocale(language.equals("hi")?new Locale(language, "IN"):new Locale(language));
        return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true";
    }
}

How to initialize the language property to the selected language in <p:selectOneMenu> in this bean?


Solution

  • Traditionally, the parameter value of language - a request parameter, could be made available using

    FacesContext context = FacesContext.getCurrentInstance();
    String language = context.getExternalContext().getRequestParameterMap().get("language");
    

    like the following,

    @Controller
    @Scope("request")
    public final class IntermediateLocaleBean
    {
        @Autowired
        private final transient LocaleBean localeBean=null;
    
        public IntermediateLocaleBean() {}
    
        public void setLanguage(String language) {
            this.language = language;
        }
    
        public String localeAction()
        {
            String language = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("language");
            localeBean.setLocale(language.equals("hi")?new Locale(language, "IN"):new Locale(language));
    
            return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true";
        }
    }
    

    But I personally dislike exposing the entire request using FacesContext unless it is absolutely necessary.


    There is an org.springframework.beans.factory.annotation.Value annotation in Spring that can be used with the Spring expression language to obtain request parameters as follows.

    @Controller
    @Scope("request")
    public final class IntermediateLocaleBean
    {
        @Value("#{request.getParameter('language')}") //Exposing the value of language.
        private String language;
    
        @Autowired
        private final transient LocaleBean localeBean=null;
    
        public IntermediateLocaleBean() {}
    
        public void setLanguage(String language) {
            this.language = language;
        }
    
        public String localeAction()
        {
            localeBean.setLocale(language.equals("hi")?new Locale(language, "IN"):new Locale(language));
            return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true";
        }
    }
    

    The value of language supplied by <p:remoteCommand> as a request parameter is now available in this bean using the @Value annotation (the getter method for language is not required in my case).

    Please suggest or add another answer, if something else is available!