BalusC と A. Tijms の著書「The Definitive Guide to JSF in Java EE 8」(および Omnifaces で同様にコーディング) で説明されているように、通常の要求と ajax 要求で発生する例外に対して、次の CustomException ハンドラーを作成しました。
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {
public CustomExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
super(wrapped);
}
@Override
public ExceptionHandler getExceptionHandler() {
return new CustomExceptionHandler(getWrapped().getExceptionHandler());
}
private class CustomExceptionHandler extends ExceptionHandlerWrapper {
private CustomExceptionHandler(ExceptionHandler wrapped) {
super(wrapped);
}
@Override
public void handle() throws FacesException {
handleException(FacesContext.getCurrentInstance());
getWrapped().handle();
}
private void handleException(FacesContext fctx) {
Iterator<ExceptionQueuedEvent> it
= getUnhandledExceptionQueuedEvents().iterator();
if (fctx == null
|| fctx.getExternalContext().isResponseCommitted()
|| !it.hasNext()) {
return;
}
Throwable t = it.next().getContext().getException();
Throwable tc = t;
while ((tc instanceof FacesException || tc instanceof ELException)
&& tc.getCause() != null) {
tc = tc.getCause();
}
renderErrorPageView(fctx, t);
it.remove();
while (it.hasNext()) {
it.next();
it.remove();
}
}
private void renderErrorPageView(FacesContext fctx, Throwable t) {
ExternalContext ctx = fctx.getExternalContext();
String uri = ctx.getRequestContextPath()
+ ctx.getRequestServletPath();
Map<String, Object> requestMap = ctx.getRequestMap();
requestMap.put(RequestDispatcher.ERROR_REQUEST_URI, uri);
requestMap.put(RequestDispatcher.ERROR_EXCEPTION, t);
String viewId = "/view/stop_error.xhtml";
Application app = fctx.getApplication();
ViewHandler viewHandler = app.getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(fctx, viewId);
fctx.setViewRoot(viewRoot);
try {
ctx.responseReset();
if (!fctx.getPartialViewContext().isAjaxRequest()) {
ctx.setResponseStatus(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
ViewDeclarationLanguage vdl
= viewHandler.getViewDeclarationLanguage(fctx, viewId);
vdl.buildView(fctx, viewRoot);
fctx.getPartialViewContext().setRenderAll(true);
vdl.renderView(fctx, viewRoot);
fctx.responseComplete();
}
catch (IOException e) {
throw new FacesException(e);
}
finally {
requestMap.remove(RequestDispatcher.ERROR_EXCEPTION);
}
}
}
}
私が持っているweb.xmlで
<error-page>
<exception-type>javax.faces.application.ViewExpredException</exception-type>
<location>/faces/view/expired.xhtml</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/faces/view/stop_error.xhtml</location>
</error-page>
通常のリクエストの場合、それは魅力のように機能します。ただし、ajax リクエストに (Runtime)Exception がある場合、非同期リクエストが何も返さない (開発モード) または何も返さない (プロダクション モード) という Java スクリプト アラート ボックスしか表示されません。上記のコードは完全に実行されますが、エラー ページは表示されません。Java 11 で Tomcat 9 と Mojarra 2.3.8 を使用しています。
http://balusc.omnifaces.org/2013/01/composite-component-with-multiple-input.htmlで説明されている複合コンポーネントを使用してテストしました。ここでは、月を変更することによってトリガーされる updateDaysIfNecessary メソッド内で IllegalStateException をスローします。それぞれのドロップダウンボックス。