jsf - Manejo de la excepción de la capa de servicio en el método frontend de Java EE
java-ee exception-handling (3)
Mantengo una aplicación web que tiene una página con la etiqueta JSF
<f:event
.
He reescrito un método en una clase de servicio para que arroje una excepción comercial.
Sin embargo, cuando se lanza la excepción comercial, no se detecta en el bean administrado y la excepción se muestra en la página.
Parece que mi código
try/catch
no funciona.
En XHTML:
<f:event listener="#{resourceBean.init(enrollment)}" type="preRenderView" />
Método de escucha en Managed Bean:
private boolean canCreateResource;
public void init(Enrollment enrollment) {
(...)
try {
canCreateResource = resourceService.canCreateResource(enrollment);
} catch (BusinessException e) {
canCreateResource = false;
}
}
Método en clase de servicio:
public boolean canCreateResource(Enrollment enrollment) {
if (...) {
if (mandateService.isCoordinator(user, course)) {
return true;
} else {
throw new BusinessException("Undefined business rule.");
}
}
return false;
}
Por lo que leí en otros sitios, supongo que tengo que implementar alguna clase de controlador de JSF. ¿Pero cuál y cómo?
EDITADO
OBS 1:
BusinessException
clase
BusinessException
extiende la clase
RuntimeException
.
OBS 2: el atributo
canCreateResource
se creó para controlar la representación de un botón.
En caso de que desee detectar una excepción que no creó usted mismo (y no puede realizar anotaciones con
@ApplicationException
), puede detectar todas las excepciones y ver si una de las causas es del tipo que desea detectar.
Puede verificar las causas de la excepción de forma recursiva:
public static <T extends Throwable> T getCauseOfType(final Throwable throwable,
final Class<T> type) {
if (throwable == null) {
return null;
}
return type.isInstance(throwable) ? (T) throwable : getCauseOfType(throwable.getCause(), type);
}
public static <T extends Throwable> boolean hasCauseOfType(final Throwable throwable,
final Class<T> type) {
return getCauseOfType(throwable, type) != null;
}
Puedes usar esto como:
try {
...
}
catch (Exception e) {
if (hasCauseOfType(e, SomeException.class)) {
// Special handling
}
else {
throw e;
}
}
Es porque arrojaste una
RuntimeException
de un EJB.
Cuando tal
RuntimeException
no se anota con
@ApplicationException
, el contenedor EJB lo envolverá en una
javax.ejb.EJBException
y lo volverá a lanzar.
Esto se hace porque las excepciones de tiempo de ejecución
generalmente
solo se usan para indicar errores en la lógica del código, es decir, errores del programador y no errores del usuario final.
Ya sabes,
NullPointerException
,
IllegalArgumentException
,
IndexOutOfBoundsException
,
NumberFormatException
y amigos.
Esto permite que el cliente EJB tenga un punto general para tales excepciones de tiempo de ejecución, como
catch (EJBException e) { There''s a bug in the service layer or in the way how we are using it! }
catch (EJBException e) { There''s a bug in the service layer or in the way how we are using it! }
Si hubiera intentado
catch (Exception e)
e inspeccionado la excepción real, entonces lo habría notado.
Arregle su clase
BusinessException
consecuencia para agregar esa anotación, luego se reconocerá como una excepción de aplicación real y no se
EJBException
en una
EJBException
:
@ApplicationException(rollback=true)
public class BusinessException extends RuntimeException {
// ...
}
Tenga en cuenta que en caso de que arroje una
RuntimeException
no sea
RuntimeException
, aún debe mantener la anotación en eso, explícitamente con
rollback=true
, porque de forma predeterminada no realizaría una reversión, al contrario que una
RuntimeException
sin la anotación.
@ApplicationException(rollback=true)
public class BusinessException extends Exception {
// ...
}
Resumido:
-
RuntimeException
lanzada desde el método transaccional EJB realizará una reversión completa, pero la excepción se incluirá enEJBException
. -
RuntimeException
con@ApplicationException
del método transaccional EJB solo realizará una reversión completa cuandorollback=true
se establece explícitamente. -
Exception
del método EJB transaccional no realizará la reversión completa. -
Exception
con@ApplicationException
del método EJB transaccional solo realizará una reversión completa cuandorollback=true
se establece explícitamente.
Tenga en cuenta que
@ApplicationException
se hereda en todas las subclases de la excepción personalizada, por lo que no necesita repetirla en todas ellas.
Lo mejor sería tenerlo como una clase abstracta.
Vea también los ejemplos en la pregunta relacionada vinculada a continuación.
Ver también:
Si el método
isCoordinator
puede lanzar una excepción, debe agregar un bloque try try dentro del método
canCreateResource
.
Puede lanzar su propia excepción o propagar la original.
En ambos casos, debe declararlo en la firma del método.
Si lanza
BusinessException
:
public void canCreateResource(Enrollment enrollment) throws BusinessException
No devuelva ningún valor. O devuelva un valor booleano pero no arroje ninguna excepción.
En el bloque catch dentro del método
init
, agregue la excepción del mensaje Facelet:
...
} catch (BusinessException e) {
this.canCreateResource = false;
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
}
}
También en su página debe agregar la etiqueta
<h:messages>
.