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.
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.
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.
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:
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 { }
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 { }
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 { }
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>
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.
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 { }
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.
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.
This guide will show you how to create a Python function decorator with a few…
This guide will show you how to fix the error Got permission denied while trying…
This guide will show you how to create a Python virtual environment on Intellij IDEA…
This tutorial will quickly show you how to to find and kill processes on Linux,…
This guide shows a possible solution for Python error Relocation R_X86_64_PC32 against symbol can not…
I condensed below a cheat sheet of Kubernetes useful commands. I will keep updating this…