Prevent NPE in Mojarra when creating initial view

Refactor JsfViewFactory to only attempt a restoreView when state is
available. This prevents a NullPointerException from being thrown
when using Mojarra with partial state saving disabled. This change
also makes Web Flow behave in a similar way to the standard
FacesServlet.

Issue: SWF-1571
This commit is contained in:
Phillip Webb
2012-11-16 14:18:53 -08:00
parent 47e6c00485
commit d31900e5f9
3 changed files with 27 additions and 1 deletions

View File

@@ -142,4 +142,13 @@ public class FlowResponseStateManager extends ResponseStateManagerWrapper {
writer.endElement("input");
}
}
/**
* Determine if the request context has existing state.
* @param context the request context
* @return {@code true} if the context has state
*/
static boolean hasState(RequestContext context) {
return (context != null) && (context.getViewScope().contains(FACES_VIEW_STATE));
}
}

View File

@@ -132,7 +132,12 @@ public class JsfViewFactory implements ViewFactory {
private UIViewRoot getViewStateViewRoot(RequestContext context, FacesContext facesContext, ViewHandler viewHandler,
String viewName) {
UIViewRoot viewRoot = viewHandler.restoreView(facesContext, viewName);
UIViewRoot viewRoot = null;
if (FlowResponseStateManager.hasState(context)) {
// Only try an initial restore if we have state (see SWF-1571)
viewRoot = viewHandler.restoreView(facesContext, viewName);
}
if (viewRoot != null) {
if (logger.isDebugEnabled()) {
logger.debug("UIViewRoot restored for '" + viewName + "'");
@@ -144,6 +149,7 @@ public class JsfViewFactory implements ViewFactory {
}
viewRoot = viewHandler.createView(facesContext, viewName);
}
return viewRoot;
}

View File

@@ -72,12 +72,15 @@ public class JsfViewFactoryTests extends TestCase {
private final MockHttpServletResponse response = new MockHttpServletResponse();
private LocalAttributeMap<Object> viewScope = new LocalAttributeMap<Object>();
protected void setUp() throws Exception {
configureJsf();
this.extContext.setNativeContext(this.servletContext);
this.extContext.setNativeRequest(this.request);
this.extContext.setNativeResponse(this.response);
RequestContextHolder.setRequestContext(this.context);
EasyMock.expect(this.context.getViewScope()).andStubReturn(this.viewScope);
EasyMock.expect(this.context.getFlashScope()).andStubReturn(this.flashMap);
EasyMock.expect(this.context.getExternalContext()).andStubReturn(this.extContext);
EasyMock.expect(this.context.getRequestParameters()).andStubReturn(
@@ -148,6 +151,7 @@ public class JsfViewFactoryTests extends TestCase {
EasyMock.expectLastCall().andReturn(true);
EasyMock.replay(new Object[] { this.context });
setupViewState();
View restoredView = this.factory.getView(this.context);
@@ -194,6 +198,7 @@ public class JsfViewFactoryTests extends TestCase {
EasyMock.expectLastCall().andReturn(true);
EasyMock.replay(new Object[] { this.context });
setupViewState();
View restoredView = this.factory.getView(this.context);
@@ -229,6 +234,7 @@ public class JsfViewFactoryTests extends TestCase {
EasyMock.expectLastCall().andReturn(true);
EasyMock.replay(new Object[] { this.context });
setupViewState();
View restoredView = this.factory.getView(this.context);
@@ -279,6 +285,7 @@ public class JsfViewFactoryTests extends TestCase {
this.context.inViewState();
EasyMock.expectLastCall().andReturn(true);
setupViewState();
EasyMock.replay(new Object[] { this.context });
this.factory.getView(this.context);
@@ -289,6 +296,10 @@ public class JsfViewFactoryTests extends TestCase {
.getExceptionQueuedEventContext().getException());
}
private void setupViewState() {
this.viewScope.put(FlowResponseStateManager.FACES_VIEW_STATE, "X");
}
private class NoExecutionLifecycle extends FlowLifecycle {
public NoExecutionLifecycle(Lifecycle delegate) {