WildFly
  1. WildFly
  2. WFLY-875

Singletons don't respect @TransactionAttribute/deployment descriptor in @PostConstruct.

    Details

    • Type: Bug Bug
    • Status: Resolved (View Workflow)
    • Priority: Major Major
    • Resolution: Out of Date Out of Date
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: EJB
    • Labels:
    • Environment:
      JBoss 7.1.1
    • Similar Issues:
      Show 10 results 

      Description

      Singletons don't respect any transaction attributes for their @PostConstruct methods and invokes them always with REQUIRED_NEW semantics. Following part of code is responsible for hardcoding these values for registered SingletonLifecycleCMTTxInterceptor factories:

      org.jboss.as.ejb3.component.singleton.SingletonComponentDescription.java

       @Override
                      public void configure(final DeploymentPhaseContext context, final ComponentDescription description, final ComponentConfiguration configuration) throws DeploymentUnitProcessingException {
       
                          configuration.addPostConstructInterceptor(new SingletonLifecycleCMTTxInterceptor.Factory(TransactionAttributeType.REQUIRES_NEW), InterceptorOrder.ComponentPostConstruct.TRANSACTION_INTERCEPTOR);
                          configuration.addPreDestroyInterceptor(new SingletonLifecycleCMTTxInterceptor.Factory(TransactionAttributeType.REQUIRES_NEW), InterceptorOrder.ComponentPreDestroy.TRANSACTION_INTERCEPTOR);
       
                          if(description.isPassivationApplicable()) {
                              configuration.addPrePassivateInterceptor(new SingletonLifecycleCMTTxInterceptor.Factory(TransactionAttributeType.REQUIRES_NEW), InterceptorOrder.ComponentPassivation.TRANSACTION_INTERCEPTOR);
                              configuration.addPostActivateInterceptor(new SingletonLifecycleCMTTxInterceptor.Factory(TransactionAttributeType.REQUIRES_NEW), InterceptorOrder.ComponentPassivation.TRANSACTION_INTERCEPTOR);
                          }
       
                          configuration.addTimeoutViewInterceptor(TimerCMTTxInterceptor.FACTORY, InterceptorOrder.View.CMT_TRANSACTION_INTERCEPTOR);
       
                      }
      

      EJB 3.1 specification says, REQUIRED, REQUIRED_NEW and NOT_SUPPORTED attributes should be supported, where in case of REQUIRED a semantic of REQUIRED_NEW trancation attribute should be used:

      4.8.3 Transaction Semantics of Initialization and Destruction

      PostConstruct and PreDestroy methods of Singletons with container-managed transactions are transactional. From the bean developer’s view there is no client of a PostConstruct or PreDestroy method.

      A PostConstruct or PreDestroy method of a Singleton with container-managed transactions has transaction attribute REQUIRED, REQUIRES_NEW, or NOT_SUPPORTED (Required , RequiresNew, or NotSupported if the deployment descriptor is used to specify the transaction attribute).

      Note that the container must start a new transaction if the REQUIRED (Required) transaction attribute is used. This guarantees, for example, that the transactional behavior of the PostConstruct method is the same regardless of whether it is initialized eagerly at container startup time or as a side effect of a first client invocation on the Singleton. The REQUIRED transaction attribute value is allowed so that specification of a transaction attribute for the Singleton PostConstruct/PreDestroy methods can be defaulted.

      So there is not a problem with REQUIRED and REQUIRED_NEW transaction attributes, but NOT_SUPPORTED attribute is just not supported

        Gliffy Diagrams

          Issue Links

            Activity

            Hide
            John Mazzitelli added a comment -

            I was just going to create this very issue. I have a replication war. I took the quickstart for singleton example, tweeked it, and now when you go to the browser, you get an error:

            "javax.ejb.EJBException: Transaction present on server in Never call (EJB3 13.6.2.6)"

            I will attach my war, which again is nothing more than the quickstart with this added to Counter.java:

            @javax.ejb.EJB MyOtherEJB myOtherEjb;

            @javax.annotation.PostConstruct
            @javax.ejb.TransactionAttribute(javax.ejb.TransactionAttributeType.NOT_SUPPORTED)
            public void init()

            { System.out.println("!!!!!!!!!!!!!! postconstruct !!!!!!!!!!!!!!"); myOtherEjb.hello(); }

            Where MyOtherEJB is:

            package org.jboss.as.quickstarts.singleton;

            @javax.ejb.Stateless
            public class MyOtherEJB {
            @javax.ejb.TransactionAttribute(javax.ejb.TransactionAttributeType.NEVER)
            public void hello()

            { System.out.println("!!!!!!!!!!!!!! MyOtherEJB.hello !!!!!!!!!!!!!!"); }

            }

            Show
            John Mazzitelli added a comment - I was just going to create this very issue. I have a replication war. I took the quickstart for singleton example, tweeked it, and now when you go to the browser, you get an error: "javax.ejb.EJBException: Transaction present on server in Never call (EJB3 13.6.2.6)" I will attach my war, which again is nothing more than the quickstart with this added to Counter.java: @javax.ejb.EJB MyOtherEJB myOtherEjb; @javax.annotation.PostConstruct @javax.ejb.TransactionAttribute(javax.ejb.TransactionAttributeType.NOT_SUPPORTED) public void init() { System.out.println("!!!!!!!!!!!!!! postconstruct !!!!!!!!!!!!!!"); myOtherEjb.hello(); } Where MyOtherEJB is: package org.jboss.as.quickstarts.singleton; @javax.ejb.Stateless public class MyOtherEJB { @javax.ejb.TransactionAttribute(javax.ejb.TransactionAttributeType.NEVER) public void hello() { System.out.println("!!!!!!!!!!!!!! MyOtherEJB.hello !!!!!!!!!!!!!!"); } }
            Hide
            John Mazzitelli added a comment -

            raising priority to major - I would argue this is more than just a minor bug. Any code that the PostConstruct wants to call (presumably to initialize parts of the app) can no longer call any EJB methods with any non-transaction transaction attribute (like NEVER). I do not know of a workaround right now.

            Show
            John Mazzitelli added a comment - raising priority to major - I would argue this is more than just a minor bug. Any code that the PostConstruct wants to call (presumably to initialize parts of the app) can no longer call any EJB methods with any non-transaction transaction attribute (like NEVER). I do not know of a workaround right now.
            Hide
            John Mazzitelli added a comment -

            this is related to EJBTHREE-2070 only the opposite (2070 is it doesn't run in a transaction, this issue is it DOES run in a transaction but you can't have it NOT run in a transaction - I want EJBTHERE-2070 back

            Show
            John Mazzitelli added a comment - this is related to EJBTHREE-2070 only the opposite (2070 is it doesn't run in a transaction, this issue is it DOES run in a transaction but you can't have it NOT run in a transaction - I want EJBTHERE-2070 back
            Hide
            John Mazzitelli added a comment -

            OK, I think I have a workaround. I'll leave it up to the AS guys to determine if this should remain at Major priority level or not. Here's the workaround (it requires a code change):

            1) Your original Singleton EJB should no longer have a @PostConstruct annotating your post-construct method. If you used this in conjunction with @Startup, you should no longer have @Startup annotating your class either. Keep your method though - but don't have it annotated with @PostConstruct, and keep the @TransactionAttribute so it is still annotated with NOT_SUPPORTED.

            2) Create a new, separate @Singleton EJB bean (call it something like "WorkaroundAS7_5330" or something ), this one annotated with @Startup if that's how you had your original singleton EJB. This new class should have your original singleton EJB injected into it (e.g. "@EJB private YourOriginalSingletonClass singleton;"). In your new singleton EJB, create a post construct method, annotate it with @PostConstruct and the body of the method is simply a call to your original EJB's postconstruct method (e.g. this.singleton.yourOriginalPostConstructMethod()). Because your original method is still annotated with NOT_SUPPORTED, the bogus tx that the AS container is giving you will be suspended. When your original post construct method is therefore called, it will not have a tx associated with it.

            Hopefully that made sense. Here's an example of that second EJB class:

            @Singleton
            @Startup
            public class WorkaroundAS7_5530 {
            @EJB
            private StartupBean startupBean;

            @PostConstruct
            @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) // this is ignored because of bug AS7-5530

            public void initWithTransactionBecauseAS75530() throws RuntimeException

            { this.startupBean.init(); // call init() which is NOT_SUPPORTED so it suspends the tx bug AS7-5530 gives us erroneously }

            }

            Show
            John Mazzitelli added a comment - OK, I think I have a workaround. I'll leave it up to the AS guys to determine if this should remain at Major priority level or not. Here's the workaround (it requires a code change): 1) Your original Singleton EJB should no longer have a @PostConstruct annotating your post-construct method. If you used this in conjunction with @Startup, you should no longer have @Startup annotating your class either. Keep your method though - but don't have it annotated with @PostConstruct, and keep the @TransactionAttribute so it is still annotated with NOT_SUPPORTED. 2) Create a new, separate @Singleton EJB bean (call it something like "WorkaroundAS7_5330" or something ), this one annotated with @Startup if that's how you had your original singleton EJB. This new class should have your original singleton EJB injected into it (e.g. "@EJB private YourOriginalSingletonClass singleton;"). In your new singleton EJB, create a post construct method, annotate it with @PostConstruct and the body of the method is simply a call to your original EJB's postconstruct method (e.g. this.singleton.yourOriginalPostConstructMethod()). Because your original method is still annotated with NOT_SUPPORTED, the bogus tx that the AS container is giving you will be suspended. When your original post construct method is therefore called, it will not have a tx associated with it. Hopefully that made sense. Here's an example of that second EJB class: @Singleton @Startup public class WorkaroundAS7_5530 { @EJB private StartupBean startupBean; @PostConstruct @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) // this is ignored because of bug AS7-5530 public void initWithTransactionBecauseAS75530() throws RuntimeException { this.startupBean.init(); // call init() which is NOT_SUPPORTED so it suspends the tx bug AS7-5530 gives us erroneously } }
            Hide
            Stephen Coy added a comment -

            This looks like it has been addressed by AS7-1848

            Show
            Stephen Coy added a comment - This looks like it has been addressed by AS7-1848
            Hide
            David Lloyd added a comment -

            It looks like this may have been fixed, can you please verify?

            Show
            David Lloyd added a comment - It looks like this may have been fixed, can you please verify?
            Hide
            Stuart Douglas added a comment -

            I fixed this a while ago.

            Show
            Stuart Douglas added a comment - I fixed this a while ago.
            Hide
            Daniel Zwicker added a comment -

            I have just hit this problem with wildfly 8.1.0. The workaround from John works.

            Show
            Daniel Zwicker added a comment - I have just hit this problem with wildfly 8.1.0. The workaround from John works.
            Hide
            Sławomir Wojtasiak added a comment - - edited

            Yes the problem still exists, but in a bit different form. Make the method public and everything should be OK and remember that only method annotations work in this specific case.

            Show
            Sławomir Wojtasiak added a comment - - edited Yes the problem still exists, but in a bit different form. Make the method public and everything should be OK and remember that only method annotations work in this specific case.

              People

              • Assignee:
                Stuart Douglas
                Reporter:
                Sławomir Wojtasiak
              • Votes:
                0 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Development