((1)) at blah.blah.blah.ActionListenerTest.test(ActionListenerTest.java:122)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.el.parser.AstValue.invoke(AstValue.java:170)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
at com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:68)
((2)) at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:99)
at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:771)
at javax.faces.component.UICommand.broadcast(UICommand.java:372)
at javax.faces.component.UIData.broadcast(UIData.java:938)
((3)) at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321)
at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296)
at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253)
at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
I've marked interesting places with ((1)), ((2)) and ((3)). The first interesting method is ((1)) - that is where we throw an unchecked exception. The exception will be catched somewhere between ((1)) and ((2)) and wrapped into the ELException class. Then this exception will be caught in ((2)) as it can be seen here (sources are taken from Sun JSF RI 1.2.12):
public void processAction(ActionEvent actionEvent) throws AbortProcessingException {
if (actionEvent == null) {
throw new NullPointerException();
}
try {
FacesContext context = FacesContext.getCurrentInstance();
ELContext elContext = context.getELContext();
methodExpression.invoke(elContext, new Object[] {actionEvent});
} catch (ELException ee) {
Throwable eeCause = ee.getCause();
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE,
"severe.event.exception_invoking_processaction"
new Object[]{
eeCause == null ? ee.getClass().getName() : eeCause.getClass().getName(),
methodExpression.getExpressionString(),
actionEvent.getComponent().getId()
});
StringWriter writer = new StringWriter(1024);
if (eeCause == null) {
ee.printStackTrace(new PrintWriter(writer));
} else {
eeCause.printStackTrace(new PrintWriter(writer));
}
LOGGER.severe(writer.toString());
}
throw eeCause == null ? new AbortProcessingException(ee.getMessage(), ee) : new AbortProcessingException(ee.getMessage(), eeCause);
}
}
As you can see processEvents catches AbortProcessingException, logs it and does nothing! That is it!
public void processEvents(FacesContext context,
EventsQueue phaseEventsQueue, boolean havePhaseEvents) {
FacesEvent event;
while (havePhaseEvents) {
try {
event = (FacesEvent) phaseEventsQueue.remove();
UIComponent source = event.getComponent();
try {
source.broadcast(event);
} catch (AbortProcessingException e) {
if (_log.isErrorEnabled()) {
UIComponent component = event.getComponent();
String id = null != component ? component
.getClientId(context) : "";
_log.error(
"Error processing faces event for the component "
+ id, e);
}
}
} catch (NoSuchElementException e) {
havePhaseEvents = false;
}
}
}
I've tried a lot of solutions to solve this, I've tried to solve it with servlets/filters/phase-listeners/action-listeners and so on with no luck! Then I've solved it with last resort - AspectJ. The following aspect does the job perfectly:
To weave Richfaces's jar I've used the maven (I use it to build the project anyway):
@Aspect
public class RichfacesErrorIntercepterAspect {
@Around("call(* javax.faces.component.UIComponent.broadcast(..)) && within (org.ajax4jsf.component.AjaxViewRoot)")
public void callToBroadcast (final ProceedingJoinPoint thisJoinPoint) throws Throwable
{
try {
thisJoinPoint.proceed ();
} catch (final AbortProcessingException e) {
throw new RuntimeException ("Exception in action listener: " + e.getMessage (), e.getCause ());
}
}
}
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<complianceLevel>1.5</complianceLevel>
<weaveDependencies>
<weaveDependency>
<groupId>org.richfaces.framework</groupId>
<artifactId>richfaces-impl</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>