Problems with @ViewScoped and @PreDestroy have been identified in the spec and a fix is slated for JSF 2.2: http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-905
You guys might want to comment on it. Stan On 11/16/2012 9:50 AM, Mark Struberg wrote: > > Hi Radu! > > Congratulations, you spotted a very deeply buried problem :) It actually has > nothing to do with CODI nor CDI. The problem is similar with every > passivation capable (==Serializable) bean: @PreDestroy is not 100% guaranteed > to get fired. > > I'm not sure if you really did hit a bug in the 2 JSF impls or a systematic > consequence of serializable objects I like to explain now: > > > Think about a @ViewScoped bean. The @PreDestroy invokes a user.logout() for > example. Now you navigate away from the page and the @ViewScoped bean gets > closed. Then press the browser back button and you will have the bean again > (restored from the viewstate map). That might lead to @PreDestroy getting > invoked multiple times. > > > Now another case: a user opens a page.xhtml in his browser. A @ViewScoped > bean gets called and if ClientSideStateSaving is activated it gets serialized > and stored inside the html page. The user just goes away or closes his > browser and this bean will never get the @PreDestroy being called. > > Something similar happens with all @SessionScoped or session related beans if > a server shuts down and passivates it's sessions. If there is a redeployment > inbetween which is not binary compatible, then those beans will never get > resurrected and never get properly destroyed because of that. > > It get's even worse if you think about Session replication to multiple nodes. > On which node should the @PreDestroy being called? And at what time? > > > Again: not sure if you did hit any of the 'natural' reasons or if it is > really a bug. If it's a bug then not in CODI but the JSF impls. > > > > LieGrue, > strub > >> ________________________________ >> From: Radu Creanga <[email protected]> >> To: [email protected] >> Sent: Friday, November 16, 2012 3:25 PM >> Subject: CODI: @ViewScoped implementation possibly flawed. >> >> >> Dear CODI devs, >> >> >> Please allow me to bring to your attention a possible flaw in the >> implementation of @ViewScoped. I apologize in advance if this is not the >> case. >> >> >> The class >> org.apache.myfaces.extensions.cdi.jsf2.impl.scope.view.ViewScopedContext >> provides the life-cycle for @ViewScoped annotated objects. An implementation >> of Context, according to the documentation: >> >> >> "[...] the context object is responsible for destroying any contextual >> instance it creates by passing the instance to Contextual.destroy(Object, >> CreationalContext). A destroyed instance must not subsequently be returned >> by get(). The context object must pass the same instance of >> CreationalContext to Contextual.destroy() that it passed to >> Contextual.create() when it created the instance." >> >> >> The ViewScopedContext implementation in question attempts to achieve this >> requirement by: >> 1. implementing javax.faces.event.SystemEventListener; >> 2. registering itself for javax.faces.event.PreDestroyViewMapEvent; >> 3. destroying Contextual instances upon receiving those events. >> >> >> The problem is that PreDestroyViewMapEvent don't seem to be fired. >> Intuitively, these events should be fired every time UIViewRoot objects are >> destroyed, but after spending hours trying to get at least one of them to >> fire I have seen none, neither on MyFaces, nor on Mojarra JSF >> implementations. I expected to see these events fired at least on session >> termination or web-app shut-down, but no luck. >> >> >> The documentation for javax.faces.event.PreDestroyViewMapEvent states: >> >> >> "This event must be published by a call to >> Application.publishEvent(javax.faces.context.FacesContext, java.lang.Class, >> java.lang.Object) when the clear method is called on the map returned from >> UIViewRoot#getViewMap." >> >> >> Is clear()required to be called anywhere? The only reference in the >> documentation where I could find such a requirement is at >> FacesContext.setViewRoot(): >> >> >> "If the current UIViewRoot is non-null, and calling equals() on the argument >> root, passing the current UIViewRoot returns false, the clear method must be >> called on the Map returned from UIViewRoot#getViewMap." >> >> >> If this is the only place where clear()on the view map is called (I suspect >> it is since I could not get any of these events to fire), which is only >> during the Invoke Application phase of the request processing lifecycle and >> during the Restore View phase of the request processing lifecycle >> (especially when a new root component is created), then most if not all >> Contextual instances created by >> org.apache.myfaces.extensions.cdi.jsf2.impl.scope.view.ViewScopedContextare >> not disposed properly. >> >> >> I was lead to this while trying to implement my own @ViewScoped context and >> could not verify that the instances I create are ever destroyed. This lead >> me to post a question on stackoverflow.com, from where I was suggested I >> take a look at the CODI implementation. From what I can tell, both >> implementations do not properly dispose of contextual objects they create, >> while offering the end-user behaviour they advertise. >> >> >> Hopefully, this is useful insight and I would be honoured to be permitted to >> get involved in coming up with a solution, assuming a problem exists. >> >> Radu Creanga >> >> >>
