From 2aa99ec0d00876ab82d17a04b1a33eadf27b3c6a Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 6 Aug 2015 15:59:41 -0400 Subject: [PATCH] isPostback preserved across redirect before render The JSF com.sun.faces.facelets.tag.jsf.ComponentSupport in 2.2.7 started using FacesContext#isPostBack to check if a new component tree is being built prior to attempting to find a child component. In Web Flow where we redirect prior to rendering, and hence lose the value of isPostback (because ResponseStateManagerImpl no longer finds the parameter with the view state), it causes components to be re-created and lose their local values. This change overrides isPostback in FlowFacesContext in order to return true in cases where the UIViewRoot has been restored from flash scope and is fully built. Issue: SWF-1645 --- .../faces/webflow/FlowFacesContext.java | 23 +++++++++++++++++-- .../faces/webflow/FlowViewHandler.java | 6 +++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java index e25cc5e4..9c960861 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2012 the original author or authors. + * Copyright 2004-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; - import javax.el.ELContext; import javax.faces.application.FacesMessage; import javax.faces.context.ExternalContext; @@ -92,6 +91,9 @@ public class FlowFacesContext extends FacesContextWrapper { private final PartialViewContext partialViewContext; + private boolean viewRootHolderFromFlashScope; + + public FlowFacesContext(RequestContext context, FacesContext wrapped) { this.context = context; this.wrapped = wrapped; @@ -259,6 +261,23 @@ public class FlowFacesContext extends FacesContextWrapper { return new FacesMessage(severity, message.getText(), null); } + /** + * This flag is set internally when the UIViewRoot is restored following a + * redirect and prior to rendering and is then checked whether to return + * {@code true} from {@link #isPostback()} so that JSF (2.2.7+) won't think + * it's building a new component tree. + * @see com.sun.faces.facelets.tag.jsf.ComponentSupport#isBuildingNewComponentTree + * @since 2.4.2 + */ + void setViewRootRestoredFromFlashScope() { + this.viewRootHolderFromFlashScope = true; + } + + @Override + public boolean isPostback() { + return (this.viewRootHolderFromFlashScope || super.isPostback()); + } + public static FlowFacesContext newInstance(RequestContext context, Lifecycle lifecycle) { FacesContext defaultFacesContext = newDefaultInstance(context, lifecycle); return new FlowFacesContext(context, defaultFacesContext); diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java index 4dd272b5..a3768f5e 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2004-2012 the original author or authors. + * Copyright 2004-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package org.springframework.faces.webflow; import java.util.Locale; - import javax.faces.application.ViewHandler; import javax.faces.application.ViewHandlerWrapper; import javax.faces.component.UIViewRoot; @@ -118,6 +117,9 @@ public class FlowViewHandler extends ViewHandlerWrapper { RequestContext context = RequestContextHolder.getRequestContext(); ViewRootHolder holder = (ViewRootHolder) context.getFlashScope().get(View.USER_EVENT_STATE_ATTRIBUTE); if (holder != null && holder.getViewRoot() != null && holder.getViewRoot().getViewId().equals(resourcePath)) { + if (facesContext instanceof FlowFacesContext) { + ((FlowFacesContext) facesContext).setViewRootRestoredFromFlashScope(); + } return holder.getViewRoot(); } else { return super.restoreView(facesContext, resourcePath);