1

I got some uncaught exception basically from an SQL operation via Primefaces AJAX call. Interestingly this uncaught exception APPEAR on FireBug's JavaScript secion as error:

<?xml version='1.0' encoding='UTF-8'?>
<partial-response><error><error-name>class javax.faces.el.EvaluationException</error-name><error-message><![CDATA[Transaction rolled back]]></error-message></error></partial-response>

and on the server.log with all stacktrace and everything.

But I am unable to to bring it to the user attention without redirecting them to a separate error page (and lost all input data).

The proper way to handle this to create validator, which I will do, but there are always possibility of unaware database problem which will only appear doing the SQL operation. So I am only talk about no validator situation.

Let say I have this JSF snippet.

    <h:form>
        <p:messages />
        <..... primefaces (AJX) some button .... action="bean.save()" />
    </h:form>

and the bean.save();

  public void save()
  {
    try
    {
       em.merge(this.data);
    }
    catch(Exception e)
    {
       // never been in here EVEN if the data can't be merge for some constraint breaking reason.
    }
  }

If there is an database error, we will not see it until the transaction ends (AFTER save()) so I can't catch it. (This is confirmed with debug walk through and the fact that adding "em.flush()" here make the whole things works).

After looked left and right, I created a PhaseListener and I am able to get the exception. However, I am unable to show that exception on <p:messages />

    public void afterPhase(final PhaseEvent event)
    {
        final Iterable exceptionEvents = event.getFacesContext().getExceptionHandler().getUnhandledExceptionQueuedEvents();
        for (final ExceptionQueuedEvent exceptionEvent : exceptionEvents)
        {
            // This print out goes (found in server.log).
            System.out.println("Problem: " + exceptionEvent.getContext().getException());
            // But this message does not.
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Problem", "Problem: " + exceptionEvent.getContext().getException()));
        }
    }

Any advice is very appreciated.

NawaMan
  • 25,129
  • 10
  • 51
  • 77

1 Answers1

1

A PhaseListener is not the right place to handle exceptions. You should be using an ExceptionHandler. The only other change you need to make in the code is that you should use Iterator to iterate over the exceptions and use Iterator#remove() to remove the handled exception from the queue. Otherwise it will still be handled by the default exception handler in flavor of that ajax response which you're seeing.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555