Uploaded image for project: 'Weld'
  1. Weld
  2. WELD-2454

@Stateful @Dependent session bean injected with @Inject into @ViewScoped backing bean does not have @PreDestroy invoked (can't be garbage collected)

    XMLWordPrintable

Details

    • Hide

      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.

      Show
      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.

    Description

      Reported in awareness of the fact that neither CDI v1.2 (maintenance JSR-346) nor CDI v2.0 JSR 365 (http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#builtin_scopes) explicitly mention @ViewScoped as a built-in CDI scope. In this sense, the report may therefore be considered a wish for future support.
      _

      When an explicitly @Dependent pseudo-scoped @Stateful session bean (or an implicitly @Dependent pseudo-scoped session bean, using default scope) is injected using CDI @Inject into a CDI-compatible @ViewScoped JSF backing bean (javax.faces.view.ViewScoped), on @PreDestroy of the backing bean the injected @Dependent @Stateful session bean does not have its @PreDestroy invoked, and it can't be garbage collected (confirmed using NetBeans Profiler).

      The same issue also happens with the OmniFaces (org.omnifaces.cdi.ViewScoped).

      Attachments

        Activity

          People

            Unassigned Unassigned
            webel_jira Darren Kelly (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: