There is a complete and very easy to use mini test web app, with complete instructions, for NetBeans-8.2.
https://github.com/webelcomau/EJBvsCDIvsJSF
The problem exhibits itself in GlassFish-5 (Weld 3.0.0) and older GlassFish-4.1.1 (older Weld version). Testing vs GlassFish-5 however requires installing and then selecting it in NetBeans-8.2 under the Project > Run option.
Open the project in NetBeans-8.2, clean and build, run.
The index shows links for 4 different backing bean cases:
1. javax.enterprise.context.RequestScoped (class Jsf23RequestBean)
2. javax.faces.view.ViewScoped (class Jsf23ViewBean)
3. org.omnifaces.cdi.ViewScoped (class OmniViewBean)
4. javax.enterprise.context.SessionScoped (class Jsf23SessionBean)
Only 2. and 3. (the ViewScoped variations) are immediately relevant for this issue report.
To run a test case, simply click on the test case link for the matching backing bean type.
In each case, the backing bean has been injected with similar sets of differently scoped session beans. The diagnostic logging indicates exactly which session bean type (see also description on GitHub page).
The session beans of interest to this issue report are:
/**
* A stateful EJB without explicit scope; Inject this into a backing bean using @Inject.
*/
@Stateful
public class StatefulInject extends StatefulCommon {
/**
* A stateful EJB with explicit dependent pseudo-scope; Inject this into a backing bean using @Inject.
*/
@Stateful
@Dependent
public class StatefulDepend extends StatefulCommon {
They are injected into the ViewScoped backing beans as:
@Inject
private StatefulInject statefulInject;
@Inject
private StatefulDepend statefulDepend;
To show the issue, click on the test case link corresponding to:
2. javax.faces.view.ViewScoped (class Jsf23ViewBean)
(TEST: CDI-friendly @Named @ViewScoped backing bean)
The page loads with server log output:
Info: StatefulEjb [1516102043958]: postConstruct
Info: StatefulInject [1516102043960]: postConstruct
Info: StatefulDepend [1516102043961]: postConstruct
Info: Jsf23ViewBean [1516102043957]: postConstruct
Info: StatefulEjb [1516102043958]: exec
Info: StatefulInject [1516102043960]: exec
Info: StatefulDepend [1516102043961]: exec
Info: StatefulRequest [1516102043964]: postConstruct
Info: StatefulRequest [1516102043964]: exec
Info: StatefulViewView [1516102043965]: postConstruct
Info: StatefulViewView [1516102043965]: exec
Info: StatefulOmniView [1516102043967]: postConstruct
Info: StatefulOmniView [1516102043967]: exec
Info: StatefulSession [1516099795164]: exec
Info: StatelessEjb [1516102043969]: postConstruct
Info: StatelessEjb [1516102043969]: exec
Info: StatelessEjb [1516102043969]: pseudoState=1
Info: StatelessInject [1516102043970]: postConstruct
Info: StatelessInject [1516102043970]: exec
Info: StatelessInject [1516102043970]: pseudoState=1
Info: StatefulRequest [1516102043964]: preDestroy
IMPORTANT: Mojarra @ViewScoped disposal is broken for GET methods. To trigger @PreDestroy on the backing bean leave the page (view) using one of the h:commandButton methods as indicated, which goes to a page done.xhtml. The log output is then:
Info: StatefulEjb [1516102184245]: postConstruct
Info: StatefulInject [1516102184247]: postConstruct
Info: StatefulDepend [1516102184248]: postConstruct
Info: Jsf23ViewBean [1516102184244]: postConstruct
Info: StatefulEjb [1516102184245]: exec
Info: StatefulInject [1516102184247]: exec
Info: StatefulDepend [1516102184248]: exec
Info: StatefulRequest [1516102184251]: postConstruct
Info: StatefulRequest [1516102184251]: exec
Info: StatefulViewView [1516102184252]: postConstruct
Info: StatefulViewView [1516102184252]: exec
Info: StatefulOmniView [1516102184255]: postConstruct
Info: StatefulOmniView [1516102184255]: exec
Info: StatefulSession [1516099795164]: exec
Info: StatelessEjb [1516102043969]: exec
Info: StatelessEjb [1516102043969]: pseudoState=2
Info: StatelessInject [1516102043970]: exec
Info: StatelessInject [1516102043970]: pseudoState=2
Info: StatefulRequest [1516102184251]: preDestroy
Note that the @PreDestroy methods of the @Stateful beans of class StatefulDepend (explicit @Dependent) and StatefulInject (implicit defaul) have NOT been invoked.
If you repeat this with the OmniFaces @ViewScoped the result is nearly the same. (The only difference is all navigation methods away from the view work correctly, the backing bean always has @PreDestroy invoked.)
Compare with the @RequestScoped backing bean case, where the @PreDestroy on the @Dependent stateful session beans is correctly invoked during its @PreDestroy:
Info: StatefulEjb [1516102350062]: postConstruct
Info: StatefulInject [1516102350063]: postConstruct
Info: StatefulDepend [1516102350064]: postConstruct
Info: Jsf23RequestBean [1516102350061]: postConstruct
Info: StatefulEjb [1516102350062]: exec
Info: StatefulInject [1516102350063]: exec
Info: StatefulDepend [1516102350064]: exec
Info: StatefulRequest [1516102350066]: postConstruct
Info: StatefulRequest [1516102350066]: exec
Info: StatefulViewView [1516102350068]: postConstruct
Info: StatefulViewView [1516102350068]: exec
Info: StatefulOmniView [1516102350070]: postConstruct
Info: StatefulOmniView [1516102350070]: exec
Info: StatefulSession [1516099795164]: exec
Info: StatelessEjb [1516102043969]: exec
Info: StatelessEjb [1516102043969]: pseudoState=3
Info: StatelessInject [1516102043970]: exec
Info: StatelessInject [1516102043970]: pseudoState=3
Info: Jsf23RequestBean [1516102350061]: preDestroy
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @EJB statefulEjb !
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @Inject statefulInject !
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @Inject statefulDepend !
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @Inject statefulRequest !
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @Inject statefulViewView !
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @Inject statefulOmniView !
Info: Jsf23RequestBean [1516102350061]: SKIP: WILL NOT force remove() on @Inject statefulSession !
Info: StatefulInject [1516102350063]: preDestroy
Info: StatefulDepend [1516102350064]: preDestroy
Info: StatefulRequest [1516102350066]: preDestroy
Note the last 3 lines; @PreDestroy is correctly invoked.