Last Updated on 15/11/2020
There are two types of exceptions in EJB: application exception and system exception. This guide will show how to identify and implement both of them.
Why two types of exceptions in EJB?
In EJB, it’s important to know whether an exception has occurred because of a business problem or a system error. That way, EJB exceptions are split in two to represent a maybe recoverable business problem (like an ordinary checked exception in Java) or a unexpected and unrecoverable issue caused by a system error or bad coding (like common runtime exceptions).
After all the concepts involved, they are just ordinary exceptions with meaningful metadata defined by annotations or XML configuration in the deployment descriptor to tell the EJB container how to deal with them.
Application Exception
EJB application exceptions are meant to describe business problems, such as an account unable to be withdrawn because of insufficient funds or a failed meeting booking attempt due to unavailable meeting rooms in the office. Such problems are often recoverable by the system, which can simply show messages to the user or propose other day to book the meeting.
Defining an Application Exception
An application exception is any checked exception except java.rmi.RemoteException
and its subclasses, or unchecked (runtime) exceptions marked with a specific annotation or via deployment descriptor. Given that, the following sections are going to describe these three approaches for defining an application exception:
Extend Exception
Any class that extends Exception
(including the Exception
class itself) but the java.rmi.RemoteException
class and its subclasses, are application exceptions:
public class MyException extends Exception { }
As stated above, the only “exception” to the rule is when you extend the java.rmi.RemoteException
, because that given exception is treated as a system exception by the container, so its subclasses:
// This is not an application exception because it extends RemoteException public class NotAnApplicationException extends RemoteException { }
Annotate runtime exceptions
Any class that extends RuntimeException
annotated with @ApplicationException
is also an application exception:
@ApplicationException public class MyOtherException extends RuntimeException { }
Any subclasses of the given runtime exception annotated with @ApplicationException
, are also application exceptions:
@ApplicationException public class MyOtherException extends RuntimeException { } public class AnotherException extends MyOtherException { }
If you’d like to disable that inheritance feature, you can use the optional parameter inherited
with value of false
:
@ApplicationException(inherited = false) public class MyOtherException extends RuntimeException { } // Not an application exception anymore public class AnotherException extends MyOtherException { }
Deployment Descriptor
The third option to define application exceptions is through the deployment descriptor element application-exception
in the META-INF/ejb-jar.xml
file. The only mandatory element is the exception-class
:
<?xml version="1.0" encoding="UTF-8"?> <ejb-jar version="3.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"> <display-name>oceejbd6-ejb</display-name> <assembly-descriptor> <application-exception> <exception-class>com.bgasparotto.oceejbd6.ejb.MyOtherException</exception-class> </application-exception> </assembly-descriptor> </ejb-jar>
Then you can remove the annotation from the exception class and it will behave the same:
public class MyOtherException extends RuntimeException { }
Application Exceptions and Transactions
The short story is, application exceptions don’t cause a transaction to be automatically rolled back by default when thrown by a business method. Instead, they are propagated to the caller (a client code or another business method) AS-IS.
However, if you’d like to change this behaviour to cause the transaction to be rolled back, use the parameter rollback
with the value true
in the annotation:
@ApplicationException(rollback = true) public class MyException extends Exception { } @ApplicationException(rollback = true) public class MyOtherException extends RuntimeException { }
Or in the deployment descriptor:
<assembly-descriptor> <application-exception> <exception-class>com.bgasparotto.oceejbd6.ejb.MyOtherException</exception-class> <rollback>true</rollback> </application-exception> </assembly-descriptor>
System Exception
On the other hand, EJB system exceptions are meant to describe system level problems, such as a failure trying to get a database connection, a failed attempt to access a network resource and so on. As you can see, the application can hardly ever recover from these type of errors, therefore, it should not try to handle them.
Defining System Exception
In short, everything that is NOT an application exception, IS a system exception. Moreover, it makes sense to have runtime exceptions being treated as unrecoverable since they usually describe a code error or a system level failure.
// This is a system exception public class MySystemException extends RuntimeException { } // This is also a system exception since it extends RemoteException public class MyOtherSystemException extends RemoteException { } // These are NOT system exceptions, so they are application exceptions instead public class NotSystemException extends Exception { // It extends Exception } @ApplicationException // This annotation makes it a application exception public class NotYetSystemException extends RuntimeException { }
System Exceptions and Transactions
In regard to system exceptions, if the current invocation is part of a transaction, when the container encounters a system exception, it marks the transaction for rollback and throws an EJBTransactionRolledBackException
.
On the contrary, if the current invocation is not part of a transaction, the EJB container wraps the system exception into an EJBException
(for local and no-interface views) or RemoteException
(for remote views) and throws it to the client.
System Exceptions and Bean Lifecycle
Unlike application exceptions, system exceptions cause the bean instance which threw the exception to be discarded from the instance pool. This rule applies to any method (business, timeout, message listener, lifecycle callback, and interceptors) of stateless, stateful and message-driven beans.
However, singleton session beans are not discarded in case of a system exception, but they will not initialise and will, in fact, be removed if such exceptions are thrown from a @PostConstruct
lifecycle callback method.
References
- JCP – JSR 318: Enterprise JavaBeans Version 3.1
- Burke, Bill; Rubinger, Andrew Lee. Enterprise JavaBeans 3.1 6th Edition.
- Frits Walraven @ Coderanch – OCEEJBD Links