Skip to content

EJB: Application Exception vs System Exception

Last Updated on 27/12/2023

Existem dois tipos de exceções em EJB: application exception e system exception. Este guia irá mostrar como identificar e implementar ambos os tipos.

Porque dois tipos de exceções em EJB?

No EJB, é importante saber quando uma exceção ocorreu devido a um problema de negócio ou um erro de sistema. Deste modo, exceções EJB são dividas em dois tipos para representar problemas de negócios possivelmente recuperáveis (como uma checked exception em Java) ou um erro inesperado e irrecuperável causado por um erro de sistema ou erros de código (como uma runtime exception).

Mesmo depois de todos os conceitos envolvidos, elas são apenas exceções comuns contendo metadados úteis para o container definidos por anotações ou XML no deployment descriptor, para dizer ao container EJB como tratá-las.

Application Exception

Application exceptions do EJB são feitas para descrever problemas de negócio, como saques bloqueados em uma conta bancária devido a fundos insuficientes ou uma falha ao tentar agendar uma sala de reunião devido a falta de salas disponíveis no escritório. Estes tipos de problemas são recuperáveis pelo sistema, o qual pode simplesmente exibir mensagens ao usuário ou sugerir uma nova data para o agendamento da reunião.

Definindo uma Application Exception

Uma application exception é qualquer checked exception exceto java.rmi.RemoteException e suas sub-classes, ou unchecked (runtime) exceptions marcadas com uma anotação específica ou definida ou via deployment descriptor. Dito isto, as próximas seções irão descrever essas três abordagens ao se definir uma application exception:

Estender Exception

Quaisquer classes que estendam Exception (incluindo a própria classe Exception) exceto a classe java.rmi.RemoteException e suas sub-classes, são application exceptions:

public class MyException extends Exception {
}

Como descrito acima, a única “exceção” para esta regra se dá quando você estende java.rmi.RemoteException, pois esta exceção e suas sub-classes são tratadas como system exceptions pelo container:

// Esta não é uma application exception pois herda de RemoteException
public class NotAnApplicationException extends RemoteException {
}

Anotar runtime exceptions

Qualquer classe que estenda RuntimeException e seja anotada com @ApplicationException também é uma application exception:

@ApplicationException
public class MyOtherException extends RuntimeException {
}

Quaisquer sub-classes de uma dada runtime exception anotada com @ApplicationException, também são application exceptions:

@ApplicationException
public class MyOtherException extends RuntimeException {
}

public class AnotherException extends MyOtherException {
}

Se você quiser desabilitar essa funcionalidade de herança, você pode passar um parâmetro opcional inherited com o valor false:

@ApplicationException(inherited = false)
public class MyOtherException extends RuntimeException {
}

// Já não é mais uma application exception
public class AnotherException extends MyOtherException {
}

Deployment Descriptor

A terceira opção para definir application exceptions é através do elemento application-exception do deployment descriptor no arquivo META-INF/ejb-jar.xml. O único elemento obrigatório é o 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>

Deste modo, você pode remover a anotação da classe de exceção que seu comportamento permanecerá o mesmo:

public class MyOtherException extends RuntimeException {
}

Application Exceptions e Transações

Em resumo, application exceptions quando lançadas por um método de negócio, por padrão não fazem com que a transação sofra um rollback automaticamente. Ao invés disto, elas são propagadas para o cliente (podendo ser até mesmo ou outro EJB) sem modificações (AS-IS).

Porém, se você quiser modificar esse comportamento para que as transações sofram o rollback, utilize o parâmetro rollback com o valor true na anotação:

@ApplicationException(rollback = true)
public class MyException extends Exception {
}

@ApplicationException(rollback = true)
public class MyOtherException extends RuntimeException {
}

Ou no deployment descriptor:

<assembly-descriptor>
	<application-exception>
		<exception-class>com.bgasparotto.oceejbd6.ejb.MyOtherException</exception-class>
		<rollback>true</rollback>
	</application-exception>
</assembly-descriptor>

System Exception

Por outro lado, system exceptions do EJB tem o objetivo de reportar problemas a nível de sistema, como uma falha ao tentar obter uma conexão de banco de dados, um erro ao tentar acessar um recurso de rede, etc. Como você pode ver, a aplicação muito dificilmente conseguirá se recuperar deste tipos de erros, então, ela não deve sequer tentar tratá-los.

Definindo System Exception

Em resumo, tudo o que não for uma application exception, É uma system exception. Além disso, faz sentido que runtime exceptions sejam tratadas como irrecuperáveis visto que elas geralmente denotam um erro de código ou uma falha a nível de sistema.

// Esta é uma a system exception
public class MySystemException extends RuntimeException {
}

// Esta também é uma system exception visto que herda de RemoteException
public class MyOtherSystemException extends RemoteException {
}

// Estas NÃO SÃO system exceptions, pois são application exceptions
public class NotSystemException extends Exception { // It extends Exception
}

@ApplicationException // Essa anotação faz com que ela seja uma application exception
public class NotYetSystemException extends RuntimeException {
}

System Exceptions e Transações

Quando falamos de system exceptions, se a invocação de métodos atual for parte de uma transação, o container marca a transação para rollback quando encontra uma system exception e por fim, lança uma EJBTransactionRolledBackException.

De outro modo, se a invocação de métodos atual não fizer parte de uma transação, o container EJB encapsula a system exception em uma EJBException (para no-view e interfaces locais) ou RemoteException (para views remotas) e a lança para o cliente.

System Exceptions e Bean Lifecycle

De modo contrário as application exceptions, system exceptions fazem com que a instância que lançou a exception seja descartada do pool de instâncias. Essa regra se aplica em qualquer método (business, timeout, message listener, lifecycle callback e interceptors) de beans to tipo stateless, stateful e message-driven.

Entretanto, session beans singleton não são descartados no caso de uma system exception, mas eles não irão inicializar corretamente e serão de fato, removidos, caso este tipo de exceção seja lançada de um método anotado com @PostConstruct.

Referências

1 thought on “EJB: Application Exception vs System Exception”

  1. Valeu pela ajuda! Conseguiu me dar uma luz sobre o que estava ocorrendo na minha aplicação e como eu tenho que fazer para que ela tenha o comportamento exato que eu preciso.

Leave a Reply

Your email address will not be published. Required fields are marked *