It's because you threw a RuntimeException
from an EJB.
When such RuntimeException
is not annotated with @ApplicationException
, then the EJB container will wrap it in an javax.ejb.EJBException
and rethrow it. This is done so because runtime exceptions are usually only used to indicate bugs in code logic, i.e. programmer's mistakes and not enduser's mistakes. You know, NullPointerException
, IllegalArgumentException
, IndexOutOfBoundsException
, NumberFormatException
and friends. This allows the EJB client to have one catch-all point for such runtime exceptions, like catch (EJBException e) { There's a bug in the service layer or in the way how we are using it! }
If you had tried catch (Exception e)
and inspected the actual exception, then you'd have noticed that.
Fix your BusinessException
class accordingly to add that annotation, it will then be recognized as a real application exception and not be wrapped in an EJBException
:
@ApplicationException(rollback=true)
public class BusinessException extends RuntimeException {
// ...
}
Do note that in case you throw an non-RuntimeException
, then you still need to keep the annotation on that, explicitly with rollback=true
, because by default it wouldn't perform a rollback, on the contrary to a RuntimeException
without the annotation.
@ApplicationException(rollback=true)
public class BusinessException extends Exception {
// ...
}
Summarized:
RuntimeException
thrown from transactional EJB method will perform full rollback, but exception will be wrapped in EJBException
.
RuntimeException
with @ApplicationException
from transactional EJB method will only perform full rollback when rollback=true
is explicitly set.
Exception
from transactional EJB method will not perform full rollback.
Exception
with @ApplicationException
from transactional EJB method will only perform full rollback when rollback=true
is explicitly set.
Note that @ApplicationException
is inherited over all subclasses of the custom exception, so you don't need to repeat it over all of them. Best would be to have it as an abstract class. See also the examples in the related question linked below.
See also:
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…