Search code examples
jsfsessioncdimanaged-bean

How to inject a http session attribute to a bean using CDI


I have some legacy code that put objects as http session attributes using code like this:

MyObject object = new MyObject();
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
sessionMap.put("attrname", object);

The old facelets accessed the code using

 @ManagedProperty("#{attrname}")
 private MyObject object;

Is there any way using CDI (@Inject) to inject this session attribute to a Bean?

In new code that uses CDI what's the better way to create and inject objects that need to be created in a controlled way.


Solution

  • Get hold of it in a session scoped managed bean with a @Produces@Named on the getter.

    @SessionScoped
    public class MyObjectProducer implements Serializable {
    
        private MyObject myObject;
    
        @Produces
        @Named("attrname")
        public MyObject getMyObject() {
            return myObject;
        }
    
        public void setMyObject(MyObject myObject) {
            this.myObject = myObject;
        }
    
    }
    

    When you set it somehow via e.g. myObjectProducer.setMyObject(myObject) elsewhere (or perhaps a CDI @Observes event), then you can inject it anywhere using @Inject @Named.

    @Inject
    @Named("attrname")
    private MyObject myObject;
    

    And yes, it's still available via #{attrname} in EL the usual way. And no, it won't be auto-created when not set, it'll remain null until you actually set it as a property of the producer class.


    Alternatively, if you really intend to keep the legacy way of setting the instance via ExternalContext#getSessionMap() (e.g. because it's third party and you can thus not change it), then you can alternatively also let the producer return it directly from the session map:

    @SessionScoped
    public class MyObjectProducer implements Serializable {
    
        @Produces
        @Named("attrname")
        public MyObject getMyObject() {
            return (MyObject) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("attrname");
        }
    
    }
    

    This however isn't guaranteed to work when injected in a non-JSF artifact, such as an arbitrary @WebServlet, as the FacesContext#getCurrentInstance() would obviously return null.