Search code examples
jsfcdimanaged-beanhttp-request-parametersmanaged-property

@ManagedProperty with request parameter not set in a @Named bean


I've a CDI managed bean wherein I'd like to set request parameters as managed properties:

import javax.inject.Named;
import javax.enterprise.context.RequestScoped;

@Named
@RequestScoped
public class ActivationBean implements Serializable {

    @ManagedProperty(value="#{param.key}")
    private String key;

    @ManagedProperty(value="#{param.id}")
    private Long id;

    // Getters+setters

The URL is domain/activate.jsf?key=98664defdb2a4f46a527043c451c3fcd&id=5, however the properties are never set and remain null.

How is this caused and how can I solve it?

I am aware that I can manually grab them from ExternalContext as below:

Long id = Long.parseLong(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"), 10);
String key = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");

However, I'd rather use injection.


Solution

  • Using @ManagedProperty on a CDI managed bean works only when you're using JSF 2.3 or newer. You'll then need the @ManagedProperty annotation from jakarta.faces.annotation/javax.faces.annotation package instead of the javax.faces.bean one, and you need to use it in combination with @Inject.

    import javax.inject.Inject;
    import javax.inject.Named;
    import javax.enterprise.context.RequestScoped;
    import javax.faces.annotation.ManagedProperty;
    // Use jakarta.* when you're already on JSF/Faces 3.0 or newer
    
    @Named
    @RequestScoped
    public class ActivationBean {
    
        @Inject @ManagedProperty("#{param.key}")
        private String key;
    
        @Inject @ManagedProperty("#{param.id}")
        private Long id;
    

    The @ManagedProperty annotation from the javax.faces.bean package works only in beans annotated with the legacy @ManagedBean annotation and has been deprecated since JSF 2.3 and removed since Faces 4.0.

    In case you're still on JSF 2.2, or you just happen to already use the JSF utility library OmniFaces, then you can also use its @Param annotation instead. It automatically infers the parameter name and type from the Java field, hereby further reducing the boilerplate.

    @Inject @Param
    private String key;
    
    @Inject @Param
    private Long id;
    

    Alternatively, you can also use the <f:viewParam> tag in the view for the purpose.

    <f:metadata>
        <f:viewParam name="key" value="#{bean.key}" />
        <f:viewParam name="id" value="#{bean.id}" />
    </f:metadata>
    

    See also