Java

EJB: Application Exception vs System Exception

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

bgasparotto

Recent Posts

Python function decorator

This guide will show you how to create a Python function decorator with a few…

2 years ago

Got permission denied while trying to connect to the Docker daemon socket

This guide will show you how to fix the error Got permission denied while trying…

2 years ago

Python virtual environment on Intellij IDEA

This guide will show you how to create a Python virtual environment on Intellij IDEA…

2 years ago

Find and kill processes on Linux and Mac by port number

This tutorial will quickly show you how to to find and kill processes on Linux,…

2 years ago

Python: Relocation R_X86_64_PC32 against symbol can not be used when making a shared object Error

This guide shows a possible solution for Python error Relocation R_X86_64_PC32 against symbol can not…

2 years ago

Kubernetes useful commands

I condensed below a cheat sheet of Kubernetes useful commands. I will keep updating this…

2 years ago