jsf java-ee exception-handling ejb service-layer

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:

  1. RuntimeException lanzada desde el método transaccional EJB realizará una reversión completa, pero la excepción se incluirá en EJBException .
  2. RuntimeException con @ApplicationException del método transaccional EJB solo realizará una reversión completa cuando rollback=true se establece explícitamente.
  3. Exception del método EJB transaccional no realizará la reversión completa.
  4. Exception con @ApplicationException del método EJB transaccional solo realizará una reversión completa cuando rollback=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> .