JSF ViewExpiredExceptionHandler NullPointerException
Я использую Apache MyFaces 2 на WebSphere Application Server 8. Я хочу реализовать пользовательский ExceptionHandler, который обрабатывает исключение ViewExpiredException.
Я использую код, который выложил BalusC. Фабрика вызывается в нужное время, но я получаю исключение NullPointerException при вызове handleNavigation здесь:
public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public ViewExpiredExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
@Override
public void handle() throws FacesException {
FacesContext facesContext = FacesContext.getCurrentInstance();
for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents()
.iterator(); iter.hasNext();) {
Throwable exception = iter.next().getContext().getException();
if (exception instanceof ViewExpiredException) {
facesContext
.getApplication()
.getNavigationHandler()
.handleNavigation(facesContext, null,
"/content/home?faces-redirect=true&expired=true");
facesContext.renderResponse();
iter.remove();
}
}
getWrapped().handle();
}
@Override
public ExceptionHandler getWrapped() {
return wrapped;
}
}
Исключение составляет:
com.ibm.ws.webcontainer.servlet.ServletWrapper service SRVE0068E: An exception was thrown by one of the service methods of the servlet [Faces Servlet] in application [My_App]. Exception created : [java.lang.NullPointerException
at org.apache.myfaces.application.NavigationHandlerImpl.getNavigationCase(NavigationHandlerImpl.java:203)
at org.apache.myfaces.application.NavigationHandlerImpl.handleNavigation(NavigationHandlerImpl.java:77)
at myapp.ViewExpiredExceptionHandler.handle(ViewExpiredExceptionHandler.java:33)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:191)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1147)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:722)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:449)
at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:125)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:92)
at myapp.auth.RequestFilter.doFilter(RequestFilter.java:35)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:192)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:89)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:919)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1016)
at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:886)
at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1655)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:195)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:452)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:511)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:305)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:276)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1650)
]
РЕДАКТИРОВАТЬ: Прежде всего / Content является каталогом в моем WebContent. Это не контекстный путь. Я изменил свой код и использовал внешнее перенаправление следующим образом:
if (exception instanceof ViewExpiredException) {
String loc = facesContext.getExternalContext()
.getRequestServletPath();
try {
facesContext.getExternalContext().redirect(loc);
//facesContext.getExternalContext().redirect("/content/home.xhtml");
//facesContext.getExternalContext().redirect("/");
} catch (IOException e) {
e.printStackTrace();
}
}
Но все равно получите то же исключение NullPointerException для FaceContext.getExternalContext(). Redirect. Но ExternalContext не является нулевым. Я получил RequestServletPath.
Так что не так с моим кодом здесь?
С наилучшими пожеланиями - veote
2 ответа
"/content/home?faces-redirect=true&expired=true"
очевидно, не признается в качестве действительного случая навигации. Невозможно сказать, что там не так, так как детали вашего окружения неясны. Является /content
контекстный путь или нет? Если так, то это должно быть опущено. Есть ли на самом деле /home.xhtml
файл? Etcetera.
Если вы все еще не можете понять это, то, вероятно, проще просто отправить перенаправление, как вам кажется, в любом случае после перенаправления.
externalContext.redirect("/content/home.xhtml?expired=true");
Обратите внимание, что это все равно приведет к 404, если URL-адрес недействителен, но, вероятно, вам будет легче его выяснить.
Я получаю похожий набор ошибок. Следуя вышеизложенному подходу, моя ручка навигации
nav.handleNavigation(fc, null, "/error");
Возвращает NPE, как указано выше (четные номера строк).
Если я изменяю, чтобы просто сделать перенаправление, я получаю:
java.lang.NullPointerException
at org.apache.myfaces.context.servlet.PartialViewContextImpl.getPartialResponseWriter(PartialViewContextImpl.java:303)
at org.primefaces.context.PrimePartialViewContext.getPartialResponseWriter(PrimePartialViewContext.java:45)
at org.apache.myfaces.context.servlet.ServletExternalContextImpl.redirect(ServletExternalContextImpl.java:452)
at my.package.CustomExceptionHandler.handle(CustomExceptionHandler.java:134)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:191)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1235)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:758)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:441)
В обоих случаях я считаю, что причина в том, что getViewRoot()
является нулем, который, очевидно, не ожидается 'getNavigationCase' или getPartialResponseWriter
,
Мне удалось исправить, используя пример в этом сообщении в блоге ( http://ovaraksin.blogspot.com/2010/10/jsf-ajax-redirect-after-session-timeout.html). Кажется, что у Mojarra и PrimeFaces (я использую PrimeFaces 3.5 с MyFaces) есть проблемы со стандартным перенаправлением в случае этой ошибки. Исправление в том случае, если
facescontext.getResponseWriter() == null && facescontext.getRenderKit() == null
и это частичный запрос и запрос AJAX, затем используйте RenderKit
создать ResponseWriter
и установить его на facescontext
,
externalContext.redirect()
потом работает.
Изменить: более конкретно, в сообщении блога, SecurityPhaseListener
имеет doRedirect(FacesContext fc, String redirectPage)
метод, который включает в себя раздел под названием:
// fix for renderer kit (Mojarra's and PrimeFaces's ajax redirect)
Я поднял этот раздел в метод ответа перенаправления, который я вызываю из блока if (exception instanceof ViewExpiredException)
РЕДАКТИРОВАТЬ ОК, окончательное решение. С помощью фрагмента кода с http://jira.icesoft.org/browse/ICE-4251 я смог реализовать это с помощью ручного навигации. Вот вызов, который я добавил из проблемы JIRA, которая выполняется в handle()
checkViewRoot(facesContext,"/error.jsf");
... вот метод
public static void checkViewRoot( FacesContext ctx, String viewId) {
if (ctx.getViewRoot() == null) {
UIViewRoot viewRoot = ctx.getApplication().getViewHandler().createView(ctx, viewId);
if (viewRoot != null) {
ctx.setViewRoot(viewRoot);
}
}
}
... И после этого handle navigation вызывается в методе handle().
facesContext
.getApplication()
.getNavigationHandler()
.handleNavigation(facesContext, null,
(redirectPage != null ? redirectPage : ""));
facesContext.renderResponse();
Обратите внимание, что по моему опыту до сих пор, viewId
Должна быть существующей страницей, отличной от той, на которую нужно перенаправить страницу.
Хорошая вещь facesmessage
Я установил с viewexpiredexception
сообщение теперь отображается на новой странице, с которой у меня были все виды проблем с перенаправлением.