Search code examples
jsfcdivaluechangelistener

Injecting a CDI SessionScoped bean into a JSF ValueChangeListener


I am trying to use a javax.faces.event.ValueChangeListener against a h:selectOneMenu like so

<h:selectOneMenu value="#{localeBean.languageCode}" onchange="submit()">
    <f:selectItem itemLabel="English" itemValue="en" />
    <f:selectItem itemLabel="German" itemValue="de" />
    <f:valueChangeListener  type="org.bitbucket.paulstat.jsf.event.ExampleValueChangeListener" />
</h:selectOneMenu>

This is the listener

import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
import javax.inject.Inject;

import org.bitbucket.paulstat.jsf.localisation.LocaleBean;

public class ExampleValueChangeListener implements ValueChangeListener {

    @Inject
    private LocaleBean localeBean;

    @Override
    public void processValueChange(ValueChangeEvent event) throws AbortProcessingException {
        localeBean.setLanguageCode(event.getNewValue().toString());
        localeBean.switchLocale();
    }

}

And the LocaleBean

import java.io.Serializable;
import java.util.Locale;

import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;

@Named
@SessionScoped
public class LocaleBean implements Serializable {

    private String languageCode;

    public void switchLocale() {
        FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale(languageCode));
    }

    public void setLanguageCode(String languageCode) {
        this.languageCode = languageCode;
    }

    public String getLanguageCode() {
        return languageCode;
    }

}

The LocaleBean doesn't appear to be being injected in the value change listener and is null. Can we mix SessionScoped CDI beans with JSF ValueChangeListeners?


Solution

  • @Inject works only in CDI managed beans. Your ExampleValueChangeListener isn't a CDI managed bean.

    Make it one. Easiest way is to put the @Named annotation on it so it's available in EL.

    @Named
    public class ExampleValueChangeListener implements ValueChangeListener {
        // ...
    }
    

    Reference it via binding instead of type.

    <f:valueChangeListener binding="#{exampleValueChangeListener}" />
    

    See also: