Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can @ApplicationException's inheritance be overridden in EJB 3.1?

Tags:

java

ejb-3.1

If I have an Exception with an @ApplicationException(inherited = true, rollback = true) but I want a subclass to not rollback. Can I just annotate the subclass with @ApplciationException(rollback = false)? Or will that not work? The spec doesn't seem to say, that I could find.

like image 298
Yishai Avatar asked Dec 26 '22 10:12

Yishai


2 Answers

The EJB 3.1 spec (JSR 318) does explain this in section 14.2.1. There is an example:

In the following example :
@ApplicationException(rollback=true)
public class ExceptionA extends RuntimeException
public class ExceptionB extends ExceptionA
@ApplicationException(inherited=false, rollback=false)
public class ExceptionC extends ExceptionB
public class ExceptionD extends ExceptionC

ExceptionA is an application exception with transaction rollback.
ExceptionB is an application exception with transaction rollback.
ExceptionC is an application exception without transaction rollback.
ExceptionD is not an application exception.
like image 132
Brett Kail Avatar answered Jan 31 '23 12:01

Brett Kail


JSR 220 does not explicitly state what should happen in this scenario. It does specify that application-exception deployment descriptor elements will override any annotated value for a specific EJB:

An application exception does not automatically result in marking the transaction for rollback unless the ApplicationException annotation is applied to the exception class and is specified with the rollback element value true or the application-exception deployment descriptor element for the exception specifies the rollback element as true. The rollback subelement of the application-exception deployment descriptor element may be explicitly specified to override the rollback value specified or defaulted by the ApplicationException annotation

This, combined with how annotations work for other Java EE components (@TransactionAttribute, @ConcurrencyManagement etc), would lead one to strongly assume that the subclass @ApplicationException annotation will override that of its parent. I confirmed this to be the case with a simple test (incomplete code shown):

@ApplicationException(inherited = true, rollback = true)
public class MyBaseException extends RuntimeException {
    // Constructors
}

public class MySubException1 extends MyBaseException {
    // Constructors
}

@ApplicationException(rollback = false)
public class MySubException2 extends MyBaseException {
    // Constructors
}

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Path("/misc/exception")
@Produces(MediaType.APPLICATION_JSON)
public class ExceptionResourceImpl {
   @Inject
   private BaseDAO baseDAO;

   public ExceptionResourceImpl() {
      super();
   }

   @GET
   @Path("/app/{id}")
   public Response getApplicationException(@PathParam("id") final String id) {
      final PaymentTypeModel model = new PaymentTypeModel();
      model.setPayment("Key" + System.currentTimeMillis());

      if ("1".equals(id)) {
         baseDAO.create(model);
         throw new MySubException1(
               "Throwing sub exception 1, default annotation behaviour");
      } else if ("2".equals(id)) {
         baseDAO.create(model);
         throw new MySubException2(
               "Throwing sub exception 2, overrides annotation behaviour");
      } else {
         return Response.status(Status.BAD_REQUEST)
               .entity("Must supply id of 1 or 2").build();
      }
   }
}

Results:

  • Requesting /misc/exception/app/1 results in an error on the screen, with no record saved to the database.
  • Requesting /misc/exception/app/2 results in an error on the screen, but the record is saved to the database, aka the annotation override to not rollback transactions was processed for MySubException2.

* EDIT *

JSR 318 does clarify the behavior of inherited ApplicationException annotations, through the use of examples.

In the following example :

@ApplicationException(rollback=true) public class ExceptionA extends RuntimeException

public class ExceptionB extends ExceptionA

@ApplicationException(inherited=false, rollback=false) public class ExceptionC extends ExceptionB

public class ExceptionD extends ExceptionC

ExceptionA is an application exception with transaction rollback. ExceptionB is an application exception with transaction rollback. ExceptionC is an application exception without transaction rollback. ExceptionD is not an application exception

This confirms my original statements and testing.

like image 21
Perception Avatar answered Jan 31 '23 13:01

Perception