You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2020/04/05 15:49:12 UTC

[struts] 01/01: WW-4789 WW-3788 Introduces helper methods to allow build fluent API

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch action-context-boost
in repository https://gitbox.apache.org/repos/asf/struts.git

commit dfda16d7432dfc1a087b6a050884611a9a5ad6ac
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Apr 5 09:59:55 2020 +0200

    WW-4789 WW-3788 Introduces helper methods to allow build fluent API
---
 .../com/opensymphony/xwork2/ActionContext.java     | 97 +++++++++++++++++++---
 .../xwork2/DefaultActionInvocation.java            |  4 +-
 .../org/apache/struts2/ServletActionContext.java   |  6 +-
 .../apache/struts2/dispatcher/HttpParameters.java  |  1 +
 .../interceptor/CreateSessionInterceptor.java      |  2 +-
 .../struts2/interceptor/ScopeInterceptor.java      | 56 ++++++-------
 .../struts2/util/InvocationSessionStore.java       | 28 +++----
 .../com/opensymphony/xwork2/ActionContextTest.java | 39 +++++----
 .../com/opensymphony/xwork2/ActionSupportTest.java | 82 +++++++++---------
 .../ConversionErrorInterceptorTest.java            | 15 ++--
 .../ActionAutowiringInterceptorTest.java           | 16 ++--
 .../ConversionErrorFieldValidatorTest.java         |  6 +-
 .../DefaultActionValidatorManagerTest.java         |  5 +-
 .../validator/DoubleRangeFieldValidatorTest.java   | 12 +--
 .../xwork2/validator/RegexFieldValidatorTest.java  | 34 ++------
 ...teConversionErrorFieldValidatorSupportTest.java |  1 -
 .../validator/VisitorFieldValidatorTest.java       | 39 +++++----
 .../validator/validators/ValidatorSupportTest.java | 43 ++++------
 .../apache/struts2/components/UIComponentTest.java |  1 -
 .../interceptor/ServletConfigInterceptorTest.java  |  6 +-
 .../StrutsConversionErrorInterceptorTest.java      |  5 +-
 .../struts2/result/ServletRedirectResultTest.java  |  4 +-
 .../struts2/util/InvocationSessionStoreTest.java   | 37 +++++----
 .../views/freemarker/FreeMarkerResultTest.java     |  9 +-
 .../freemarker/FreemarkerResultMockedTest.java     |  9 +-
 .../apache/struts2/views/jsp/AbstractTagTest.java  |  9 +-
 .../org/apache/struts2/views/jsp/I18nTagTest.java  |  1 -
 .../org/apache/struts2/views/jsp/IfTagTest.java    |  1 -
 .../org/apache/struts2/views/jsp/URLTagTest.java   | 10 +--
 .../apache/struts2/views/jsp/ui/FormTagTest.java   |  2 -
 .../org/apache/struts2/EmbeddedJSPResultTest.java  | 16 ++--
 .../struts2/views/java/simple/AbstractTest.java    |  2 +-
 .../apache/struts2/dispatcher/ChartResultTest.java |  2 -
 .../apache/struts2/json/JSONInterceptorTest.java   | 13 ++-
 .../org/apache/struts2/StrutsJUnit4TestCase.java   |  2 +-
 .../org/apache/struts2/StrutsPortletTestCase.java  |  2 +-
 .../java/org/apache/struts2/StrutsTestCase.java    |  2 +-
 .../portlet/result/PortletVelocityResult.java      |  4 +-
 .../struts2/views/jsp/PortletUrlTagTest.java       | 11 +--
 .../rest/ContentTypeHandlerManagerTest.java        |  4 +-
 .../struts2/rest/RestWorkflowInterceptorTest.java  |  5 +-
 .../views/velocity/result/VelocityResult.java      |  4 +-
 .../views/velocity/result/VelocityResultTest.java  |  1 -
 43 files changed, 343 insertions(+), 305 deletions(-)

diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
index 95baaab..6647356 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
@@ -21,6 +21,7 @@ package com.opensymphony.xwork2;
 import com.opensymphony.xwork2.conversion.impl.ConversionData;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.util.ValueStack;
+import com.sun.org.apache.bcel.internal.generic.ACONST_NULL;
 import org.apache.struts2.StrutsException;
 import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.dispatcher.HttpParameters;
@@ -62,7 +63,10 @@ public class ActionContext implements Serializable {
 
     /**
      * Constant for the name of the action being executed.
+     *
+     * @deprecated used helper methods instead
      */
+    @Deprecated
     public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
 
     /**
@@ -196,7 +200,9 @@ public class ActionContext implements Serializable {
      * Sets the action's application context.
      *
      * @param application the action's application context.
+     * @deprecated use {@link #withApplication(Map)} instead
      */
+    @Deprecated
     public void setApplication(Map<String, Object> application) {
         put(APPLICATION, application);
     }
@@ -223,7 +229,9 @@ public class ActionContext implements Serializable {
      * Sets conversion errors which occurred when executing the action.
      *
      * @param conversionErrors a Map of errors which occurred when executing the action.
+     * @deprecated use {@link #withConversionErrors(Map)} instead
      */
+    @Deprecated
     public void setConversionErrors(Map<String, ConversionData> conversionErrors) {
         put(CONVERSION_ERRORS, conversionErrors);
     }
@@ -238,8 +246,7 @@ public class ActionContext implements Serializable {
         Map<String, ConversionData> errors = (Map) get(CONVERSION_ERRORS);
 
         if (errors == null) {
-            errors = new HashMap<>();
-            setConversionErrors(errors);
+            errors = withConversionErrors(new HashMap<>()).getConversionErrors();
         }
 
         return errors;
@@ -275,7 +282,9 @@ public class ActionContext implements Serializable {
      * Sets the name of the current Action in the ActionContext.
      *
      * @param name the name of the current action.
+     * @deprecated use {@link #withActionName(String)} instead
      */
+    @Deprecated
     public void setName(String name) {
         put(ACTION_NAME, name);
     }
@@ -290,6 +299,15 @@ public class ActionContext implements Serializable {
     }
 
     /**
+     * Gets the name of the current Action.
+     *
+     * @return the name of the current action.
+     */
+    public String getActionName() {
+        return (String) get(ACTION_NAME);
+    }
+
+    /**
      * Sets the action parameters.
      *
      * @param parameters the parameters for the current action.
@@ -313,7 +331,9 @@ public class ActionContext implements Serializable {
      * Sets a map of action session values.
      *
      * @param session the session values.
+     * @deprecated use {@link #withSession(Map)} instead
      */
+    @Deprecated
     public void setSession(Map<String, Object> session) {
         put(SESSION, session);
     }
@@ -331,7 +351,9 @@ public class ActionContext implements Serializable {
      * Sets the OGNL value stack.
      *
      * @param stack the OGNL value stack.
+     * @deprecated Use {@link #withValueStack(ValueStack)} instead
      */
+    @Deprecated
     public void setValueStack(ValueStack stack) {
         put(VALUE_STACK, stack);
     }
@@ -404,31 +426,86 @@ public class ActionContext implements Serializable {
         return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE);
     }
 
-    public void setServletContext(ServletContext servletContext) {
+    public ActionContext withServletContext(ServletContext servletContext) {
         put(StrutsStatics.SERVLET_CONTEXT, servletContext);
+        return this;
     }
 
-    public void setServletRequest(HttpServletRequest request) {
+    public ActionContext withServletRequest(HttpServletRequest request) {
         put(StrutsStatics.HTTP_REQUEST, request);
+        return this;
     }
 
-    public void setServletResponse(HttpServletResponse response) {
+    public ActionContext withServletResponse(HttpServletResponse response) {
         put(StrutsStatics.HTTP_RESPONSE, response);
+        return this;
     }
 
     public PageContext getPageContext() {
         return (PageContext) get(StrutsStatics.PAGE_CONTEXT);
     }
 
-    public void setPageContext(PageContext pageContext) {
-        put(StrutsStatics.PAGE_CONTEXT, pageContext);
-    }
-
     public ActionMapping getActionMapping() {
         return (ActionMapping) get(StrutsStatics.ACTION_MAPPING);
     }
 
-    public void setActionMapping(ActionMapping actionMapping) {
+    public ActionContext withActionMapping(ActionMapping actionMapping) {
         put(StrutsStatics.ACTION_MAPPING, actionMapping);
+        return this;
+    }
+
+    public ActionContext withApplication(Map<String, Object> application) {
+        put(APPLICATION, application);
+        return this;
+    }
+
+    public ActionContext withSession(Map<String, Object> session) {
+        put(SESSION, session);
+        return this;
+    }
+
+    public ActionContext withParameters(HttpParameters parameters) {
+        put(PARAMETERS, parameters);
+        return this;
     }
+
+    public ActionContext withActionName(String actionName) {
+        put(ACTION_NAME, actionName);
+        return this;
+    }
+
+    public ActionContext withValueStack(ValueStack valueStack) {
+        put(VALUE_STACK, valueStack);
+        return this;
+    }
+
+    public ActionContext withPageContext(PageContext pageContext) {
+        put(StrutsStatics.PAGE_CONTEXT, pageContext);
+        return this;
+    }
+
+    public ActionContext withPageContextOrClear(ActionContext actionContext) {
+        if (actionContext == null) {
+            put(StrutsStatics.PAGE_CONTEXT, null);
+        } else {
+            put(StrutsStatics.PAGE_CONTEXT, actionContext.getPageContext());
+        }
+        return this;
+    }
+
+    public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
+        put(CONVERSION_ERRORS, conversionErrors);
+        return this;
+    }
+
+    public ActionContext withContainer(Container container) {
+        put(CONTAINER, container);
+        return this;
+    }
+
+    public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
+        put(ACTION_INVOCATION, actionInvocation);
+        return this;
+    }
+
 }
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
index b38d8d0..c256ad5 100644
--- a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
@@ -395,8 +395,8 @@ public class DefaultActionInvocation implements ActionInvocation {
             contextMap.put("action", action);
         }
 
-        invocationContext = ActionContext.of(contextMap);
-        invocationContext.setName(proxy.getActionName());
+        invocationContext = ActionContext.of(contextMap)
+            .withActionName(proxy.getActionName());
 
         createInterceptors(proxy);
 
diff --git a/core/src/main/java/org/apache/struts2/ServletActionContext.java b/core/src/main/java/org/apache/struts2/ServletActionContext.java
index c9840dc..24a4422 100644
--- a/core/src/main/java/org/apache/struts2/ServletActionContext.java
+++ b/core/src/main/java/org/apache/struts2/ServletActionContext.java
@@ -102,7 +102,7 @@ public class ServletActionContext implements StrutsStatics {
      * @param request the HTTP servlet request object.
      */
     public static void setRequest(HttpServletRequest request) {
-        ActionContext.getContext().setServletRequest(request);
+        ActionContext.getContext().withServletRequest(request);
     }
 
     /**
@@ -120,7 +120,7 @@ public class ServletActionContext implements StrutsStatics {
      * @param response the HTTP servlet response object.
      */
     public static void setResponse(HttpServletResponse response) {
-        ActionContext.getContext().setServletResponse(response);
+        ActionContext.getContext().withServletResponse(response);
     }
 
     /**
@@ -147,6 +147,6 @@ public class ServletActionContext implements StrutsStatics {
      * @param servletContext The servlet context to use
      */
     public static void setServletContext(ServletContext servletContext) {
-        ActionContext.getContext().setServletContext(servletContext);
+        ActionContext.getContext().withServletContext(servletContext);
     }
 }
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/HttpParameters.java b/core/src/main/java/org/apache/struts2/dispatcher/HttpParameters.java
index d17b71c..7746f2d 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/HttpParameters.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/HttpParameters.java
@@ -26,6 +26,7 @@ import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
diff --git a/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java
index 9091220..b927c13 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java
@@ -93,7 +93,7 @@ public class CreateSessionInterceptor extends AbstractInterceptor {
         if (httpSession == null) {
             LOG.debug("Creating new HttpSession and new SessionMap in ServletActionContext");
             servletRequest.getSession(true);
-            invocation.getInvocationContext().setSession(new SessionMap<>(servletRequest));
+            invocation.getInvocationContext().withSession(new SessionMap<>(servletRequest));
         }
         return invocation.invoke();
     }
diff --git a/core/src/main/java/org/apache/struts2/interceptor/ScopeInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ScopeInterceptor.java
index b83c7e9..08afd6e 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/ScopeInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/ScopeInterceptor.java
@@ -232,7 +232,7 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
         return o;
     }
 
-    private static Map locks = new IdentityHashMap();
+    private static Map<Object, Object> locks = new IdentityHashMap<>();
 
     static void lock(Object o, ActionInvocation invocation) throws Exception {
         synchronized (o) {
@@ -262,7 +262,7 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
     }
 
     protected void after(ActionInvocation invocation, String result) throws Exception {
-        Map ses = ActionContext.getContext().getSession();
+        Map<String, Object> ses = ActionContext.getContext().getSession();
         if ( ses != null) {
             unlock(ses);
         }
@@ -271,18 +271,18 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
 
     protected void before(ActionInvocation invocation) throws Exception {
         invocation.addPreResultListener(this);
-        Map ses = ActionContext.getContext().getSession();
-        if (ses == null && autoCreateSession) {
-            ses = new SessionMap(ServletActionContext.getRequest());
-            ActionContext.getContext().setSession(ses);
+        Map<String, Object> session = ActionContext.getContext().getSession();
+        if (session == null && autoCreateSession) {
+            session = new SessionMap<>(ServletActionContext.getRequest());
+            ActionContext.getContext().withSession(session);
         }
 
-        if ( ses != null) {
-            lock(ses, invocation);
+        if ( session != null) {
+            lock(session, invocation);
         }
 
         String key = getKey(invocation);
-        Map app = ActionContext.getContext().getApplication();
+        Map<String, Object> app = ActionContext.getContext().getApplication();
         final ValueStack stack = ActionContext.getContext().getValueStack();
 
         LOG.debug("scope interceptor before");
@@ -304,14 +304,14 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
             return;
         }
 
-        if (ses == null) {
+        if (session == null) {
             LOG.debug("No HttpSession created... Cannot set session scoped variables");
             return;
         }
 
-        if (session != null && (!"start".equals(type))) {
-            for (String string : session) {
-                Object attribute = ses.get(key + string);
+        if (this.session != null && (!"start".equals(type))) {
+            for (String string : this.session) {
+                Object attribute = session.get(key + string);
                 if (attribute != null) {
                     LOG.debug("Session scoped variable set {} = {}", string, String.valueOf(attribute));
                     stack.setValue(string, nullConvert(attribute));
@@ -329,38 +329,38 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
      */
     public void beforeResult(ActionInvocation invocation, String resultCode) {
         String key = getKey(invocation);
-        Map app = ActionContext.getContext().getApplication();
+        Map<String, Object> application = ActionContext.getContext().getApplication();
         final ValueStack stack = ActionContext.getContext().getValueStack();
 
-        if (application != null)
-            for (String string : application) {
+        if (this.application != null)
+            for (String string : this.application) {
                 Object value = stack.findValue(string);
                 LOG.debug("Application scoped variable saved {} = {}", string, String.valueOf(value));
 
                 //if( value != null)
-                app.put(key + string, nullConvert(value));
+                application.put(key + string, nullConvert(value));
             }
 
         boolean ends = "end".equals(type);
 
-        Map ses = ActionContext.getContext().getSession();
-        if (ses != null) {
+        Map<String, Object> session = ActionContext.getContext().getSession();
+        if (session != null) {
 
-            if (session != null) {
-                for (String string : session) {
+            if (this.session != null) {
+                for (String string : this.session) {
                     if (ends) {
-                        ses.remove(key + string);
+                        session.remove(key + string);
                     } else {
                         Object value = stack.findValue(string);
                         LOG.debug("Session scoped variable saved {} = {}", string, String.valueOf(value));
 
                         // Null value should be scoped too
                         //if( value != null)
-                        ses.put(key + string, nullConvert(value));
+                        session.put(key + string, nullConvert(value));
                     }
                 }
             }
-            unlock(ses);
+            unlock(session);
         } else {
             LOG.debug("No HttpSession created... Cannot save session scoped variables.");
         }
@@ -406,15 +406,15 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
      * @see com.opensymphony.xwork2.interceptor.Interceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
      */
     public String intercept(ActionInvocation invocation) throws Exception {
-        String result = null;
-        Map ses = ActionContext.getContext().getSession();
+        String result;
+        Map<String, Object> session = ActionContext.getContext().getSession();
         before(invocation);
         try {
             result = invocation.invoke();
             after(invocation, result);
         } finally {
-            if (ses != null) {
-                unlock(ses);
+            if (session != null) {
+                unlock(session);
             }
         }
 
diff --git a/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java b/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java
index 2696599..795022c 100644
--- a/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java
+++ b/core/src/main/java/org/apache/struts2/util/InvocationSessionStore.java
@@ -60,15 +60,13 @@ public class InvocationSessionStore {
             // WW-5026 - Preserve the previous PageContext (even if null) and restore it to the
             // ActionContext after loading the savedInvocation context.  The saved context's PageContext
             // would already be closed at this point (causing failures if used for output).
-            final ActionContext savedActionContext = savedInvocation.getInvocationContext();
             final ActionContext previousActionContext = ActionContext.getContext();
-            ActionContext.bind(savedActionContext);
-            savedActionContext.setValueStack(savedInvocation.getStack());
-            if (previousActionContext != null) {
-                savedActionContext.setPageContext(previousActionContext.getPageContext());
-            } else {
-                savedActionContext.setPageContext(null);
-            }
+
+            savedInvocation
+                .getInvocationContext()
+                .withPageContextOrClear(previousActionContext)
+                .withValueStack(savedInvocation.getStack())
+                .bind();
         }
 
         return savedInvocation;
@@ -84,13 +82,13 @@ public class InvocationSessionStore {
      */
     public static void storeInvocation(String key, String token, ActionInvocation invocation) {
         InvocationContext invocationContext = new InvocationContext(invocation, token);
-        Map invocationMap = getInvocationMap();
+        Map<String, Object> invocationMap = getInvocationMap();
         invocationMap.put(key, invocationContext);
         setInvocationMap(invocationMap);
     }
 
-    static void setInvocationMap(Map invocationMap) {
-        Map session = ActionContext.getContext().getSession();
+    static void setInvocationMap(Map<String, Object> invocationMap) {
+        Map<String, Object> session = ActionContext.getContext().getSession();
 
         if (session == null) {
             throw new IllegalStateException("Unable to access the session.");
@@ -99,17 +97,17 @@ public class InvocationSessionStore {
         session.put(INVOCATION_MAP_KEY, invocationMap);
     }
 
-    static Map getInvocationMap() {
-        Map session = ActionContext.getContext().getSession();
+    static Map<String, Object> getInvocationMap() {
+        Map<String, Object> session = ActionContext.getContext().getSession();
 
         if (session == null) {
             throw new IllegalStateException("Unable to access the session.");
         }
 
-        Map invocationMap = (Map) session.get(INVOCATION_MAP_KEY);
+        Map<String, Object> invocationMap = (Map<String, Object>) session.get(INVOCATION_MAP_KEY);
 
         if (invocationMap == null) {
-            invocationMap = new HashMap();
+            invocationMap = new HashMap<>();
             setInvocationMap(invocationMap);
         }
 
diff --git a/core/src/test/java/com/opensymphony/xwork2/ActionContextTest.java b/core/src/test/java/com/opensymphony/xwork2/ActionContextTest.java
index 8651b95..f5f9af2 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ActionContextTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ActionContextTest.java
@@ -34,30 +34,31 @@ import java.util.Map;
  */
 public class ActionContextTest extends XWorkTestCase {
 
-    private static final String APPLICATION_KEY = "com.opensymphony.xwork2.ActionContextTest.application";
-    private static final String SESSION_KEY = "com.opensymphony.xwork2.ActionContextTest.session";
-    private static final String PARAMETERS_KEY = "com.opensymphony.xwork2.ActionContextTest.params";
-    private static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContextTest.actionName";
+    private static final String APPLICATION_KEY = ActionContextTest.class.getName() + ".application";
+    private static final String SESSION_KEY = ActionContextTest.class.getName() + ".session";
+    private static final String PARAMETERS_KEY = ActionContextTest.class.getName() + ".params";
+    private static final String ACTION_NAME = ActionContextTest.class.getName() + ".actionName";
 
     private ActionContext context;
+    private Map<String, Object> application = new HashMap<>();
+    private Map<String, Object> session = new HashMap<>();
+    private Map<String, Object> params = new HashMap<>();
 
     @Override public void setUp() throws Exception {
         super.setUp();
         ValueStack valueStack = container.getInstance(ValueStackFactory.class).createValueStack();
         Map<String, Object> extraContext = valueStack.getContext();
-        Map<String, Object> application = new HashMap<>();
-        application.put(APPLICATION_KEY, APPLICATION_KEY);
 
-        Map<String, Object> session = new HashMap<>();
+        application.put(APPLICATION_KEY, APPLICATION_KEY);
         session.put(SESSION_KEY, SESSION_KEY);
-
-        Map<String, Object> params = new HashMap<>();
         params.put(PARAMETERS_KEY, PARAMETERS_KEY);
-        extraContext.put(ActionContext.APPLICATION, application);
-        extraContext.put(ActionContext.SESSION, session);
-        extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
-        extraContext.put(ActionContext.ACTION_NAME, ACTION_NAME);
-        context = ActionContext.of(extraContext).bind();
+
+        context = ActionContext.of(extraContext)
+            .withApplication(application)
+            .withSession(session)
+            .withParameters(HttpParameters.create(params).build())
+            .withActionName(ACTION_NAME)
+            .bind();
     }
 
     public void testContextParams() {
@@ -80,9 +81,7 @@ public class ActionContextTest extends XWorkTestCase {
     }
 
     public void testApplication() {
-        Map<String, Object> app = new HashMap<>();
-        context.setApplication(app);
-        assertEquals(app, context.getApplication());
+        assertEquals(application, context.getApplication());
     }
 
     public void testContextMap() {
@@ -93,8 +92,8 @@ public class ActionContextTest extends XWorkTestCase {
     }
 
     public void testParameters() {
-        context.setParameters(HttpParameters.create().build());
-        assertEquals(0, context.getParameters().keySet().size());
+        assertEquals(1, context.getParameters().keySet().size());
+        assertEquals(PARAMETERS_KEY, context.getParameters().get(PARAMETERS_KEY).getValue());
     }
 
     public void testConversionErrors() {
@@ -103,7 +102,7 @@ public class ActionContextTest extends XWorkTestCase {
         assertEquals(0, errors.size());
 
         Map<String, ConversionData> errors2 = new HashMap<>();
-        context.setConversionErrors(errors);
+        context.withConversionErrors(errors);
         assertEquals(errors2, context.getConversionErrors());
     }
 
diff --git a/core/src/test/java/com/opensymphony/xwork2/ActionSupportTest.java b/core/src/test/java/com/opensymphony/xwork2/ActionSupportTest.java
index 2fad4c7..1443d95 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ActionSupportTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ActionSupportTest.java
@@ -52,19 +52,19 @@ public class ActionSupportTest extends XWorkTestCase {
     }
 
     public void testNothingDoneOnActionSupport() throws Exception {
-        assertEquals(false, as.hasErrors());
+        assertFalse(as.hasErrors());
 
         assertNotNull(as.getActionErrors());
         assertEquals(0, as.getActionErrors().size());
-        assertEquals(false, as.hasActionErrors());
+        assertFalse(as.hasActionErrors());
 
         assertNotNull(as.getActionMessages());
         assertEquals(0, as.getActionMessages().size());
-        assertEquals(false, as.hasActionMessages());
+        assertFalse(as.hasActionMessages());
 
         assertNotNull(as.getFieldErrors());
         assertEquals(0, as.getFieldErrors().size());
-        assertEquals(false, as.hasFieldErrors());
+        assertFalse(as.hasFieldErrors());
 
         assertNull(as.getText(null));
 
@@ -84,16 +84,16 @@ public class ActionSupportTest extends XWorkTestCase {
         }
 
 
-        assertNull(as.getText(null, (List) null));
+        assertNull(as.getText(null, (List<?>) null));
         assertNull(as.getText(null, (String) null));
         assertNull(as.getText(null, (String[]) null));
 
-        assertNull(as.getText(null, (String) null, (List) null));
-        assertNull(as.getText(null, (String) null, (String) null));
-        assertNull(as.getText(null, (String) null, (String[]) null));
+        assertNull(as.getText(null, null, (List<?>) null));
+        assertNull(as.getText(null, null, (String) null));
+        assertNull(as.getText(null, null, (String[]) null));
 
-        assertNull(as.getText(null, (String) null, (List) null, (ValueStack) null));
-        assertNull(as.getText(null, (String) null, (String[]) null, (ValueStack) null));
+        assertNull(as.getText(null, null, (List<?>) null, null));
+        assertNull(as.getText(null, null, (String[]) null, null));
 
         assertNotNull(as.getLocale());
         assertEquals(ActionContext.getContext().getLocale(), as.getLocale());
@@ -103,49 +103,49 @@ public class ActionSupportTest extends XWorkTestCase {
     }
 
     public void testActionErrors() {
-        assertEquals(false, as.hasActionErrors());
+        assertFalse(as.hasActionErrors());
         assertEquals(0, as.getActionErrors().size());
         as.addActionError("Damm");
         assertEquals(1, as.getActionErrors().size());
         assertEquals("Damm", as.getActionErrors().iterator().next());
-        assertEquals(true, as.hasActionErrors());
-        assertEquals(true, as.hasErrors());
+        assertTrue(as.hasActionErrors());
+        assertTrue(as.hasErrors());
 
         as.clearErrorsAndMessages();
-        assertEquals(false, as.hasActionErrors());
-        assertEquals(false, as.hasErrors());
+        assertFalse(as.hasActionErrors());
+        assertFalse(as.hasErrors());
     }
 
     public void testActionMessages() {
-        assertEquals(false, as.hasActionMessages());
+        assertFalse(as.hasActionMessages());
         assertEquals(0, as.getActionMessages().size());
         as.addActionMessage("Killroy was here");
         assertEquals(1, as.getActionMessages().size());
         assertEquals("Killroy was here", as.getActionMessages().iterator().next());
-        assertEquals(true, as.hasActionMessages());
+        assertTrue(as.hasActionMessages());
 
-        assertEquals(false, as.hasActionErrors()); // does not count as a error
-        assertEquals(false, as.hasErrors()); // does not count as a error
+        assertFalse(as.hasActionErrors()); // does not count as a error
+        assertFalse(as.hasErrors()); // does not count as a error
 
         as.clearErrorsAndMessages();
-        assertEquals(false, as.hasActionMessages());
-        assertEquals(false, as.hasErrors());
+        assertFalse(as.hasActionMessages());
+        assertFalse(as.hasErrors());
     }
 
     public void testFieldErrors() {
-        assertEquals(false, as.hasFieldErrors());
+        assertFalse(as.hasFieldErrors());
         assertEquals(0, as.getFieldErrors().size());
         as.addFieldError("username", "Admin is not allowed as username");
         List<String> errors = as.getFieldErrors().get("username");
         assertEquals(1, errors.size());
         assertEquals("Admin is not allowed as username", errors.get(0));
 
-        assertEquals(true, as.hasFieldErrors());
-        assertEquals(true, as.hasErrors());
+        assertTrue(as.hasFieldErrors());
+        assertTrue(as.hasErrors());
 
         as.clearErrorsAndMessages();
-        assertEquals(false, as.hasFieldErrors());
-        assertEquals(false, as.hasErrors());
+        assertFalse(as.hasFieldErrors());
+        assertFalse(as.hasErrors());
     }
 
     public void testLocale() {
@@ -172,11 +172,11 @@ public class ActionSupportTest extends XWorkTestCase {
         assertTrue(mas.hasActionMessages());
     }
 
-    public void testSimpleGetTexts() throws Exception {
+    public void testSimpleGetTexts() {
         checkGetTexts(mas);
     }
 
-    public void testSimpleGetTextsWithInjectedTextProvider() throws Exception {
+    public void testSimpleGetTextsWithInjectedTextProvider() {
         ActionContext.getContext().setLocale(new Locale("da"));
         MyActionSupport mas = new MyActionSupport();
 
@@ -196,14 +196,12 @@ public class ActionSupportTest extends XWorkTestCase {
         assertEquals("Hello World", mas.getText("hello", "this is default"));
         assertEquals("this is default", mas.getText("not.in.bundle", "this is default"));
 
-        List nullList = null;
-        assertEquals("Hello World", mas.getText("hello", nullList));
+        assertEquals("Hello World", mas.getText("hello", (List<?>) null));
 
-        String[] nullStrings = null;
-        assertEquals("Hello World", mas.getText("hello", nullStrings));
+        assertEquals("Hello World", mas.getText("hello", (String[]) null));
     }
 
-    public void testGetTextsWithArgs() throws Exception {
+    public void testGetTextsWithArgs() {
         assertEquals("Hello World", mas.getText("hello", "this is default", "from me")); // no args in bundle
         assertEquals("Hello World from me", mas.getText("hello.0", "this is default", "from me"));
         assertEquals("this is default", mas.getText("not.in.bundle", "this is default", "from me"));
@@ -212,7 +210,7 @@ public class ActionSupportTest extends XWorkTestCase {
         assertEquals("not.in.bundle", mas.getText("not.in.bundle"));
     }
 
-    public void testGetTextsWithListArgs() throws Exception {
+    public void testGetTextsWithListArgs() {
         List<Object> args = new ArrayList<>();
         args.add("Santa");
         args.add("loud");
@@ -230,11 +228,11 @@ public class ActionSupportTest extends XWorkTestCase {
 
         assertEquals("not.in.bundle", mas.getText("not.in.bundle", args));
 
-        assertEquals("Hello World", mas.getText("hello", "this is default", (List) null));
-        assertEquals("this is default", mas.getText("not.in.bundle", "this is default", (List) null));
+        assertEquals("Hello World", mas.getText("hello", "this is default", (List<?>) null));
+        assertEquals("this is default", mas.getText("not.in.bundle", "this is default", (List<?>) null));
     }
 
-    public void testGetTextsWithArrayArgs() throws Exception {
+    public void testGetTextsWithArrayArgs() {
         String[] args = {"Santa", "loud"};
         assertEquals("Hello World", mas.getText("hello", "this is default", args)); // no args in bundle
         assertEquals("Hello World Santa", mas.getText("hello.0", "this is default", args)); // only 1 arg in bundle
@@ -254,7 +252,7 @@ public class ActionSupportTest extends XWorkTestCase {
         assertEquals("this is default", mas.getText("not.in.bundle", "this is default", (String[]) null));
     }
 
-    public void testGetTextsWithListAndStack() throws Exception {
+    public void testGetTextsWithListAndStack() {
         ActionContext.getContext().setLocale(new Locale("da"));
         MyActionSupport mas = container.inject(MyActionSupport.class);
 
@@ -272,7 +270,7 @@ public class ActionSupportTest extends XWorkTestCase {
         assertEquals("this is default Santa speaking loud", mas.getText("not.in.bundle", "this is default {0} speaking {1}", args, stack));
     }
 
-    public void testGetTextsWithArrayAndStack() throws Exception {
+    public void testGetTextsWithArrayAndStack() {
         ActionContext.getContext().setLocale(new Locale("da"));
         MyActionSupport mas = container.inject(MyActionSupport.class);
 
@@ -288,12 +286,12 @@ public class ActionSupportTest extends XWorkTestCase {
         assertEquals("this is default Santa speaking loud", mas.getText("not.in.bundle", "this is default {0} speaking {1}", args, stack));
     }
 
-    public void testGetBundle() throws Exception {
+    public void testGetBundle() {
         ResourceBundle rb = ResourceBundle.getBundle(MyActionSupport.class.getName(), new Locale("da"));
         assertEquals(rb, mas.getTexts(MyActionSupport.class.getName()));
     }
 
-    public void testFormattingSupport() throws Exception {
+    public void testFormattingSupport() {
         ActionContext.getContext().getValueStack().push(mas);
 
         mas.setVal(234d);
@@ -303,7 +301,7 @@ public class ActionSupportTest extends XWorkTestCase {
         assertEquals("234,0", formatted);
     }
 
-    public void testFormattingSupportWithConversionError() throws Exception {
+    public void testFormattingSupportWithConversionError() {
         ActionContext.getContext().getConversionErrors().put("val", new ConversionData(new String[]{"4567def"}, Double.class));
         ActionContext.getContext().setLocale(new Locale("da"));
         MyActionSupport mas = new MyActionSupport();
diff --git a/core/src/test/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptorTest.java b/core/src/test/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptorTest.java
index 6c7ec9c..22a9c28 100644
--- a/core/src/test/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptorTest.java
@@ -90,8 +90,6 @@ public class ConversionErrorInterceptorTest extends XWorkTestCase {
 
     /**
      * See WW-3668
-     *
-     * @throws Exception
      */
     public void testWithPreResultListenerAgainstMaliciousCode() throws Exception {
         conversionErrors.put("foo", new ConversionData("\" + #root + \"", int.class));
@@ -128,10 +126,10 @@ public class ConversionErrorInterceptorTest extends XWorkTestCase {
     }
 
     private ActionContext createActionContext() {
-        ActionContext ac = ActionContext.of(stack.getContext()).bind();
-        ac.setConversionErrors(conversionErrors);
-        ac.setValueStack(stack);
-        return ac;
+        return ActionContext.of(stack.getContext())
+            .withConversionErrors(conversionErrors)
+            .withValueStack(stack)
+            .bind();
     }
 
     @Override
@@ -141,9 +139,10 @@ public class ConversionErrorInterceptorTest extends XWorkTestCase {
         mockInvocation = new Mock(ActionInvocation.class);
         invocation = (ActionInvocation) mockInvocation.proxy();
         stack = ActionContext.getContext().getValueStack();
-        context = ActionContext.of(stack.getContext()).bind();
         conversionErrors = new HashMap<>();
-        context.setConversionErrors(conversionErrors);
+        context = ActionContext.of(stack.getContext())
+            .withConversionErrors(conversionErrors)
+            .bind();
         mockInvocation.matchAndReturn("getInvocationContext", context);
         mockInvocation.expect("addPreResultListener", C.isA(PreResultListener.class));
         mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptorTest.java b/core/src/test/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptorTest.java
index a48fee7..afcd262 100644
--- a/core/src/test/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptorTest.java
@@ -77,12 +77,13 @@ public class ActionAutowiringInterceptorTest extends XWorkTestCase {
     }
 
     protected void loadSpringApplicationContextIntoApplication(ApplicationContext appContext) {
-        Map<String, Object> context = new HashMap<>();
-        ActionContext actionContext = ActionContext.of(context).bind();
-
         Map<String, Object> application = new HashMap<>();
         application.put(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appContext);
-        actionContext.setApplication(application);
+
+        Map<String, Object> context = new HashMap<>();
+        ActionContext.of(context)
+            .withApplication(application)
+            .bind();
     }
 
     public void testLoadsApplicationContextUsingWebApplicationContextUtils() throws Exception {
@@ -104,10 +105,9 @@ public class ActionAutowiringInterceptorTest extends XWorkTestCase {
     }
 
     public void testIfApplicationContextIsNullThenBeanWillNotBeWiredUp() throws Exception {
-        Map<String, Object> context = new HashMap<>();
-        ActionContext actionContext = ActionContext.of(context).bind();
-
-        actionContext.setApplication(new HashMap<>());
+        ActionContext.of(new HashMap<>())
+            .withApplication(new HashMap<>())
+            .bind();
 
         ActionAutowiringInterceptor interceptor = new ActionAutowiringInterceptor();
         interceptor.init();
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/ConversionErrorFieldValidatorTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/ConversionErrorFieldValidatorTest.java
index 4207962..913fa9b 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/ConversionErrorFieldValidatorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/ConversionErrorFieldValidatorTest.java
@@ -49,11 +49,13 @@ public class ConversionErrorFieldValidatorTest extends XWorkTestCase {
     public void setUp() throws Exception {
         super.setUp();
         ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext context = ActionContext.of(stack.getContext()).bind();
 
         Map<String, ConversionData> conversionErrors = new HashMap<>();
         conversionErrors.put("foo", new ConversionData("bar", Integer.class));
-        context.setConversionErrors(conversionErrors);
+        ActionContext.of(stack.getContext())
+            .withConversionErrors(conversionErrors)
+            .bind();
+
         validator = new ConversionErrorFieldValidator();
         validationAware = new ValidationAwareSupport();
 
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java
index 5335d49..b320feb 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/DefaultActionValidatorManagerTest.java
@@ -67,8 +67,9 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
         actionValidatorManager.setValidatorFactory((ValidatorFactory)mockValidatorFactory.proxy());
 
         stubValueStack = new StubValueStack();
-        ActionContext actionContext = ActionContext.of(new HashMap<>()).bind();
-        actionContext.setValueStack(stubValueStack);
+        ActionContext.of(new HashMap<>())
+            .withValueStack(stubValueStack)
+            .bind();
 
         DefaultFileManagerFactory factory = new DefaultFileManagerFactory();
         factory.setContainer(container);
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/DoubleRangeFieldValidatorTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/DoubleRangeFieldValidatorTest.java
index c71a013..de9a944 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/DoubleRangeFieldValidatorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/DoubleRangeFieldValidatorTest.java
@@ -99,7 +99,6 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         ValueStack stack = ActionContext.getContext().getValueStack();
         stack.push(prod);
-        ActionContext.getContext().setValueStack(stack);
 
         val.setMinInclusive(0d);
         val.setMaxInclusive(10d);
@@ -115,7 +114,6 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         ValueStack stack = ActionContext.getContext().getValueStack();
         stack.push(prod);
-        ActionContext.getContext().setValueStack(stack);
 
         val.setMinInclusive(0d);
         val.setMaxInclusive(30d);
@@ -129,7 +127,6 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         ValueStack stack = ActionContext.getContext().getValueStack();
         stack.push(prod);
-        ActionContext.getContext().setValueStack(stack);
 
         val.setMinInclusive(0d);
         val.setMaxInclusive(10d);
@@ -151,7 +148,6 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         ValueStack stack = ActionContext.getContext().getValueStack();
         stack.push(prod);
-        ActionContext.getContext().setValueStack(stack);
 
         val.setFieldName("price");
 
@@ -160,7 +156,7 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         val.setMaxInclusive(9.95d);
         val.validate(prod); // should pass
-        assertTrue(!context.hasErrors());
+        assertFalse(context.hasErrors());
         assertEquals(9.95d, val.getMaxInclusive());
 
         val.setMaxExclusive(9.95d);
@@ -176,7 +172,6 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         ValueStack stack = ActionContext.getContext().getValueStack();
         stack.push(prod);
-        ActionContext.getContext().setValueStack(stack);
 
         val.setFieldName("price");
 
@@ -185,7 +180,7 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
 
         val.setMinInclusive(9.95d);
         val.validate(prod); // should pass
-        assertTrue(!context.hasErrors());
+        assertFalse(context.hasErrors());
 
         val.setMinExclusive(9.95d);
         val.validate(prod); // should not pass
@@ -193,9 +188,6 @@ public class DoubleRangeFieldValidatorTest extends XWorkTestCase {
     }
 
     public void testNoValue() throws Exception {
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         val.setFieldName("price");
 
         DelegatingValidatorContext context = new DelegatingValidatorContext(new ValidationAwareSupport(), tpf);
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/RegexFieldValidatorTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/RegexFieldValidatorTest.java
index b5495d2..df7f505 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/RegexFieldValidatorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/RegexFieldValidatorTest.java
@@ -53,9 +53,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setUsername("Secret");
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("^Sec.*");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
@@ -73,9 +70,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setUsername("Secret "); // must end with one whitespace
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setTrim(false);
         validator.setRegex("^Sec.*\\s");
@@ -94,9 +88,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setUsername("Superman");
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("^Sec.*");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
@@ -108,7 +99,7 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         assertTrue(validator.getValidatorContext().hasFieldErrors());
         List<String> msgs = validator.getValidatorContext().getFieldErrors().get("username");
         assertNotNull(msgs);
-        assertTrue(msgs.size() == 1); // should contain 1 error message
+        assertEquals(1, msgs.size()); // should contain 1 error message
 
         // when failing the validator will not add action errors/msg
         assertFalse(validator.getValidatorContext().hasActionErrors());
@@ -119,9 +110,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setUsername("NoExpression");
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("^Sec.*");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
@@ -135,26 +123,23 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         assertFalse(validator.getValidatorContext().hasFieldErrors());
     }
 
-    public void testGetExpression() throws Exception {
+    public void testGetExpression() {
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("^Hello.*");
         assertEquals("^Hello.*", validator.getRegex());
     }
 
-    public void testIsTrimmed() throws Exception {
+    public void testIsTrimmed() {
         RegexFieldValidator validator = new RegexFieldValidator();
-        assertEquals(true, validator.isTrimed());
+        assertTrue(validator.isTrimed());
         validator.setTrim(false);
-        assertEquals(false, validator.isTrimed());
+        assertFalse(validator.isTrimed());
     }
 
     public void testEmptyName() throws Exception {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setUsername("");
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("^Sec.*");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
@@ -172,9 +157,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setAge(33);
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("[0-9][0-9]");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
@@ -192,9 +174,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setFriends(new String[]{"Alice", "Matt"});
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("A([a-zA-Z]*)");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
@@ -217,9 +196,6 @@ public class RegexFieldValidatorTest extends XWorkTestCase {
         MyTestPerson testPerson = new MyTestPerson();
         testPerson.setCars(Arrays.asList("Audi", "BMW"));
 
-        ValueStack stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
         RegexFieldValidator validator = new RegexFieldValidator();
         validator.setRegex("A([a-zA-Z]*)");
         validator.setValidatorContext(new DummyValidatorContext(new Object(), tpf));
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/RepopulateConversionErrorFieldValidatorSupportTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/RepopulateConversionErrorFieldValidatorSupportTest.java
index be49dcd..5b5075a 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/RepopulateConversionErrorFieldValidatorSupportTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/RepopulateConversionErrorFieldValidatorSupportTest.java
@@ -88,7 +88,6 @@ public class RepopulateConversionErrorFieldValidatorSupportTest extends XWorkTes
 		ValueStack stack = ActionContext.getContext().getValueStack();
 		MockActionInvocation invocation = new MockActionInvocation();
 		invocation.setStack(stack);
-		ActionContext.getContext().setValueStack(stack);
 		ActionContext.getContext().setActionInvocation(invocation);
 		
 		String[] conversionErrorValue = new String[] { "some value" };
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/VisitorFieldValidatorTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/VisitorFieldValidatorTest.java
index 7116753..fd1d3a0 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/VisitorFieldValidatorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/VisitorFieldValidatorTest.java
@@ -18,19 +18,27 @@
  */
 package com.opensymphony.xwork2.validator;
 
-import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.TestBean;
+import com.opensymphony.xwork2.XWorkTestCase;
 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import com.opensymphony.xwork2.conversion.impl.ConversionData;
-
 import org.easymock.EasyMock;
 
-import java.util.*;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * VisitorFieldValidatorTest
  *
  * @author Jason Carreira
- *         Created Aug 4, 2003 1:26:01 AM
+ * Created Aug 4, 2003 1:26:01 AM
  */
 public class VisitorFieldValidatorTest extends XWorkTestCase {
 
@@ -43,7 +51,7 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
         action = container.inject(VisitorValidatorTestAction.class);
 
         TestBean bean = action.getBean();
-        Calendar cal = new GregorianCalendar(1900, 1, 1);
+        Calendar cal = new GregorianCalendar(1900, Calendar.FEBRUARY, 1);
         bean.setBirth(cal.getTime());
         bean.setCount(-1);
 
@@ -56,7 +64,7 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
         EasyMock.expect(invocation.invoke()).andReturn(Action.SUCCESS).anyTimes();
         EasyMock.expect(proxy.getMethod()).andReturn("execute").anyTimes();
         EasyMock.expect(proxy.getConfig()).andReturn(config).anyTimes();
-        
+
 
         EasyMock.replay(invocation);
         EasyMock.replay(proxy);
@@ -106,8 +114,8 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
     }
 
     public void testCollectionValidation() throws Exception {
-        List testBeanList = action.getTestBeanList();
-        TestBean testBean = (TestBean) testBeanList.get(0);
+        List<TestBean> testBeanList = action.getTestBeanList();
+        TestBean testBean = testBeanList.get(0);
         testBean.setName("foo");
         validate("validateList");
 
@@ -140,7 +148,7 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
         assertEquals(3, fieldErrors.size());
         assertTrue(fieldErrors.containsKey("bean.count"));
         assertTrue(fieldErrors.containsKey("bean.name"));
-        assertTrue(!fieldErrors.containsKey("bean.birth"));
+        assertFalse(fieldErrors.containsKey("bean.birth"));
 
         //the error from the action should be there too
         assertTrue(fieldErrors.containsKey("context"));
@@ -152,7 +160,7 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
 
         Map<String, List<String>> fieldErrors = action.getFieldErrors();
         assertEquals(3, fieldErrors.size());
-        assertTrue(!fieldErrors.containsKey("bean.count"));
+        assertFalse(fieldErrors.containsKey("bean.count"));
         assertTrue(fieldErrors.containsKey("bean.name"));
         assertTrue(fieldErrors.containsKey("bean.birth"));
 
@@ -166,13 +174,13 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
 
         Map<String, List<String>> fieldErrors = action.getFieldErrors();
         assertEquals(5, fieldErrors.size());
-        assertTrue(!fieldErrors.containsKey("bean.count"));
+        assertFalse(fieldErrors.containsKey("bean.count"));
         assertTrue(fieldErrors.containsKey("bean.name"));
         assertTrue(fieldErrors.containsKey("bean.birth"));
 
         assertTrue(fieldErrors.containsKey("bean.child.name"));
         assertTrue(fieldErrors.containsKey("bean.child.birth"));
-        
+
         //the error from the action should be there too
         assertTrue(fieldErrors.containsKey("context"));
     }
@@ -181,14 +189,14 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
         //add conversion error
         Map<String, ConversionData> conversionErrors = new HashMap<>();
         conversionErrors.put("bean.child.count", new ConversionData("bar", Integer.class));
-        ActionContext.getContext().setConversionErrors(conversionErrors);
+        ActionContext.getContext().withConversionErrors(conversionErrors);
 
         validate("visitorChildValidation");
         assertTrue(action.hasFieldErrors());
 
         Map<String, List<String>> fieldErrors = action.getFieldErrors();
         assertEquals(6, fieldErrors.size());
-        assertTrue(!fieldErrors.containsKey("bean.count"));
+        assertFalse(fieldErrors.containsKey("bean.count"));
         assertTrue(fieldErrors.containsKey("bean.name"));
         assertTrue(fieldErrors.containsKey("bean.birth"));
 
@@ -209,8 +217,7 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
     }
 
     private void validate(String context) throws ValidationException {
-        ActionContext actionContext = ActionContext.getContext();
-        actionContext.setName(context);
+        ActionContext.getContext().withActionName(context);
         container.getInstance(ActionValidatorManager.class).validate(action, context);
     }
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java
index 42a6b2f..b9b805c 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java
@@ -21,36 +21,27 @@ package com.opensymphony.xwork2.validator.validators;
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.XWorkTestCase;
 import com.opensymphony.xwork2.ognl.OgnlValueStack;
-import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.ValueStackFactory;
 import com.opensymphony.xwork2.validator.ValidationException;
 
-/**
- * @author tmjee
- * @version $Date$ $Id$
- */
 public class ValidatorSupportTest extends XWorkTestCase {
 
-	public void testConditionalParseExpression()  throws Exception {
-		ValueStack oldStack = ActionContext.getContext().getValueStack();
-		try {
-			OgnlValueStack stack = (OgnlValueStack) container.getInstance(ValueStackFactory.class).createValueStack();
-			stack.getContext().put(ActionContext.CONTAINER, container);
-			stack.getContext().put("something", "somevalue");
-			ActionContext.getContext().setValueStack(stack);
-			ValidatorSupport validator = new ValidatorSupport() {
-				public void validate(Object object) throws ValidationException {
-				}
-			};
-            validator.setValueStack(ActionContext.getContext().getValueStack());
-
-			String result1 = validator.parse("${#something}", String.class).toString();
-
-			assertEquals(result1, "somevalue");
-		}
-		finally {
-			ActionContext.getContext().setValueStack(oldStack);
-		}
-	}
+    public void testConditionalParseExpression() {
+        OgnlValueStack stack = (OgnlValueStack) container.getInstance(ValueStackFactory.class).createValueStack();
+        stack.getContext().put(ActionContext.CONTAINER, container);
+        stack.getContext().put("something", "somevalue");
+
+        ActionContext.of(stack.getContext()).bind();
+
+        ValidatorSupport validator = new ValidatorSupport() {
+            public void validate(Object object) throws ValidationException {
+            }
+        };
+        validator.setValueStack(ActionContext.getContext().getValueStack());
+
+        String result1 = validator.parse("${#something}", String.class).toString();
+
+        assertEquals(result1, "somevalue");
+    }
 
 }
diff --git a/core/src/test/java/org/apache/struts2/components/UIComponentTest.java b/core/src/test/java/org/apache/struts2/components/UIComponentTest.java
index addd7e2..65df34e 100644
--- a/core/src/test/java/org/apache/struts2/components/UIComponentTest.java
+++ b/core/src/test/java/org/apache/struts2/components/UIComponentTest.java
@@ -245,7 +245,6 @@ public class UIComponentTest extends AbstractUITagTest {
     public void testFormComponentDisposeItselfFromComponentStack() throws Exception {
         configurationManager.clearContainerProviders();
         configurationManager.addContainerProvider(new TestConfigurationProvider());
-        ActionContext.getContext().setValueStack(stack);
 
         request.setupGetServletPath("/testAction");
 
diff --git a/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java
index 20057e2..7829f26 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java
@@ -195,12 +195,12 @@ public class ServletConfigInterceptorTest extends StrutsInternalTestCase {
     }
 
     public void testApplicationAware() throws Exception {
-        ApplicationAware mock = (ApplicationAware) createMock(ApplicationAware.class);
+        ApplicationAware mock = createMock(ApplicationAware.class);
 
         MockActionInvocation mai = createActionInvocation(mock);
 
         Map<String, Object> app = new HashMap<String, Object>();
-        mai.getInvocationContext().setApplication(app);
+        mai.getInvocationContext().withApplication(app);
 
         mock.setApplication(app);
         expectLastCall().times(1);
@@ -216,7 +216,7 @@ public class ServletConfigInterceptorTest extends StrutsInternalTestCase {
         MockActionInvocation mai = createActionInvocation(mock);
 
         Map<String, Object> app = new HashMap<>();
-        mai.getInvocationContext().setApplication(app);
+        mai.getInvocationContext().withApplication(app);
 
         mock.withApplication(app);
         expectLastCall().times(1);
diff --git a/core/src/test/java/org/apache/struts2/interceptor/StrutsConversionErrorInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/StrutsConversionErrorInterceptorTest.java
index 4077dde..17d5fb4 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/StrutsConversionErrorInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/StrutsConversionErrorInterceptorTest.java
@@ -83,9 +83,10 @@ public class StrutsConversionErrorInterceptorTest extends StrutsInternalTestCase
         mockInvocation = new Mock(ActionInvocation.class);
         invocation = (ActionInvocation) mockInvocation.proxy();
         stack = ActionContext.getContext().getValueStack();
-        context = ActionContext.of(stack.getContext()).bind();
         conversionErrors = new HashMap<>();
-        context.setConversionErrors(conversionErrors);
+        context = ActionContext.of(stack.getContext())
+            .withConversionErrors(conversionErrors)
+            .bind();
         mockInvocation.matchAndReturn("getInvocationContext", context);
         mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
         mockInvocation.expectAndReturn("getStack", stack);
diff --git a/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java b/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java
index 67cd45d..a1c046a 100644
--- a/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java
+++ b/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java
@@ -455,8 +455,8 @@ public class ServletRedirectResultTest extends StrutsInternalTestCase implements
             .addResultConfigs(results).build();
 
         ActionContext ac = ActionContext.getContext();
-        ac.setServletRequest((HttpServletRequest) requestMock.proxy());
-        ac.setServletResponse((HttpServletResponse) responseMock.proxy());
+        ac.withServletRequest((HttpServletRequest) requestMock.proxy());
+        ac.withServletResponse((HttpServletResponse) responseMock.proxy());
 
         MockActionInvocation ai = new MockActionInvocation();
         ai.setInvocationContext(ac);
diff --git a/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java b/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java
index 357a42e..b581812 100644
--- a/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java
+++ b/core/src/test/java/org/apache/struts2/util/InvocationSessionStoreTest.java
@@ -60,9 +60,7 @@ public class InvocationSessionStoreTest extends StrutsInternalTestCase {
     public void testValueStackReset() {
         ActionContext actionContext = ActionContext.getContext();
         assertEquals(stack, actionContext.getValueStack());
-        InvocationSessionStore.storeInvocation(INVOCATION_KEY, TOKEN_VALUE, invocation);
-        actionContext.setValueStack(null);
-        assertNull(actionContext.getValueStack());
+
         InvocationSessionStore.loadInvocation(INVOCATION_KEY, TOKEN_VALUE);
         assertEquals(stack, actionContext.getValueStack());
     }
@@ -102,27 +100,30 @@ public class InvocationSessionStoreTest extends StrutsInternalTestCase {
     }
 
     public void testStoreAndLoadPreservesPageContext() {
-        ActionContext actionContext = ActionContext.getContext();
+        // Create mock PageContext to put with the current context (simulating a PageContext
+        // associated with the current (active) process flow).  In real-world processing it
+        // will usually be null, but if non-null it should be preserved/restored upon load of the
+        // saved context.
+        MockPageContext mockPreviousPageContext = new MockPageContext();
 
         // Create mock PageContext to put with the saved context (simulating a PageContext previously
         // used and closed after generating JSP output).
         MockPageContext mockSavedPageContext = new MockPageContext();
-        actionContext.setPageContext(mockSavedPageContext);
+        ActionContext actionContext = ActionContext.getContext()
+            .withPageContext(mockSavedPageContext);
+
         assertEquals(mockSavedPageContext, ActionContext.getContext().getPageContext());
 
         InvocationSessionStore.storeInvocation(INVOCATION_KEY, TOKEN_VALUE, invocation);
 
-        ActionContext actionContext2 = ActionContext.of(new HashMap<>()).bind();
-        actionContext2.setSession(session);
+        ActionContext actionContext2 = ActionContext.of(new HashMap<>())
+            .withSession(session)
+            .withPageContext(mockPreviousPageContext)
+            .bind();
 
         assertEquals(actionContext2, ActionContext.getContext());
 
-        // Create mock PageContext to put with the current context (simulating a PageContext 
-        // associated with the current (active) process flow).  In real-world processing it
-        // will usually be null, but if non-null it should be preserved/restored upon load of the
-        // saved context.
-        MockPageContext mockPreviousPageContext = new MockPageContext();
-        actionContext2.setPageContext(mockPreviousPageContext);
+        actionContext2.withPageContext(mockPreviousPageContext);
         assertEquals(mockPreviousPageContext, ActionContext.getContext().getPageContext());
 
         InvocationSessionStore.loadInvocation(INVOCATION_KEY, TOKEN_VALUE);
@@ -134,16 +135,16 @@ public class InvocationSessionStoreTest extends StrutsInternalTestCase {
         super.setUp();
         stack = ActionContext.getContext().getValueStack();
 
-        ActionContext actionContext = ActionContext.of(stack.getContext()).bind();
-
         session = new HashMap<>();
-        actionContext.setSession(session);
+
+        ActionContext actionContext = ActionContext.of(stack.getContext())
+            .withSession(session)
+            .withValueStack(stack)
+            .bind();
 
         invocationMock = new Mock(ActionInvocation.class);
         invocation = (ActionInvocation) invocationMock.proxy();
         invocationMock.matchAndReturn("getInvocationContext", actionContext);
-
-        actionContext.setValueStack(stack);
         invocationMock.matchAndReturn("getStack", stack);
 
         Mock proxyMock = new Mock(ActionProxy.class);
diff --git a/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java b/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java
index 0e386cb..935d2ae 100644
--- a/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java
+++ b/core/src/test/java/org/apache/struts2/views/freemarker/FreeMarkerResultTest.java
@@ -134,10 +134,11 @@ public class FreeMarkerResultTest extends StrutsInternalTestCase {
         servletContext = new StrutsMockServletContext();
         stack = ActionContext.getContext().getValueStack();
 
-        context = ActionContext.of(stack.getContext()).bind();
-        context.setServletResponse(response);
-        context.setServletRequest(request);
-        context.setServletContext(servletContext);
+        context = ActionContext.of(stack.getContext())
+            .withServletResponse(response)
+            .withServletRequest(request)
+            .withServletContext(servletContext)
+            .bind();
 
         servletContext.setAttribute(FreemarkerManager.CONFIG_SERVLET_CONTEXT_KEY, null);
 
diff --git a/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java b/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java
index cfc3e67..cd3ce51 100644
--- a/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java
+++ b/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java
@@ -246,10 +246,11 @@ public class FreemarkerResultMockedTest extends StrutsInternalTestCase {
         request = new MockHttpServletRequest();
         stack = ActionContext.getContext().getValueStack();
 
-        context = ActionContext.of(stack.getContext()).bind();
-        context.setServletResponse(response);
-        context.setServletRequest(request);
-        context.setServletContext(servletContext);
+        context = ActionContext.of(stack.getContext())
+            .withServletResponse(response)
+            .withServletRequest(request)
+            .withServletContext(servletContext)
+            .bind();
 
         servletContext.setAttribute(FreemarkerManager.CONFIG_SERVLET_CONTEXT_KEY, null);
 
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/AbstractTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/AbstractTagTest.java
index eb410ac..75fb008 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/AbstractTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/AbstractTagTest.java
@@ -121,10 +121,11 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
         extraContext.remove(ActionContext.LOCALE);
         stack.getContext().putAll(extraContext);
 
-        ActionContext actionContext = ActionContext.of(context).bind();
-        actionContext.setServletRequest(request);
-        actionContext.setServletResponse(response);
-        actionContext.setServletContext(servletContext);
+        ActionContext actionContext = ActionContext.of(context)
+            .withServletRequest(request)
+            .withServletResponse(response)
+            .withServletContext(servletContext)
+            .bind();
     }
 
     protected void tearDown() throws Exception {
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java
index aaccb47..6b5ac86 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/I18nTagTest.java
@@ -43,7 +43,6 @@ public class I18nTagTest extends StrutsInternalTestCase {
 
         // create the mock http servlet request
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
-        ActionContext.getContext().setValueStack(stack);
         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
 
         // create the mock page context
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/IfTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/IfTagTest.java
index cb4ccdd..4537e9a 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/IfTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/IfTagTest.java
@@ -323,7 +323,6 @@ public class IfTagTest extends StrutsInternalTestCase {
 
         // create the mock http servlet request
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
-        ActionContext.getContext().setValueStack(stack);
         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
 
         // create the mock page context
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java
index 4fb3b0d..50f7811 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java
@@ -556,11 +556,11 @@ public class URLTagTest extends AbstractUITagTest {
         extraContext.remove(ActionContext.LOCALE);
         stack.getContext().putAll(extraContext);
 
-        ActionContext actionContext = ActionContext.of(context).bind();
-        actionContext.setServletRequest(request);
-        actionContext.setServletResponse(response);
-        actionContext.setServletContext(servletContext);
-
+        ActionContext actionContext = ActionContext.of(context)
+            .withServletRequest(request)
+            .withServletResponse(response)
+            .withServletContext(servletContext)
+            .bind();
 
         // Make sure we have an action invocation available
         ActionContext.getContext().setActionInvocation(new DefaultActionInvocation(null, true));
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java
index 27d79ce..4ff5b1f 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/FormTagTest.java
@@ -341,8 +341,6 @@ public class FormTagTest extends AbstractUITagTest {
     }
 
     private void prepareMockInvocation() throws Exception {
-        ActionContext.getContext().setValueStack(stack);
-
         ActionConfig config = new ActionConfig.Builder("", "name", "").build();
         ActionInvocation invocation = EasyMock.createNiceMock(ActionInvocation.class);
         ActionProxy proxy = EasyMock.createNiceMock(ActionProxy.class);
diff --git a/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java b/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
index f0e42fe..ceaa8df 100644
--- a/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
+++ b/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
@@ -329,12 +329,6 @@ public class EmbeddedJSPResultTest extends TestCase {
 
         EasyMock.replay(request);
 
-        ActionContext actionContext = ActionContext.of(new HashMap<>()).bind();
-        actionContext.setParameters(HttpParameters.create(params).build());
-        actionContext.setServletRequest(request);
-        actionContext.setServletResponse(response);
-        actionContext.setServletContext(context);
-
         //mock value stack
         Map<String, Object> stackContext = new HashMap<>();
         ValueStack valueStack = EasyMock.createNiceMock(ValueStack.class);
@@ -362,9 +356,15 @@ public class EmbeddedJSPResultTest extends TestCase {
 
         EasyMock.replay(container);
         stackContext.put(ActionContext.CONTAINER, container);
-        actionContext.setContainer(container);
 
-        actionContext.setValueStack(valueStack);
+        ActionContext.of(new HashMap<>())
+            .withParameters(HttpParameters.create(params).build())
+            .withServletRequest(request)
+            .withServletResponse(response)
+            .withServletContext(context)
+            .withContainer(container)
+            .withValueStack(valueStack)
+            .bind();
     }
 
 }
diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java
index 322f1de..aa14c67 100644
--- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java
+++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java
@@ -122,7 +122,7 @@ public abstract class AbstractTest extends TestCase {
         replay(container);
 
         ActionContext actionContext = ActionContext.of(stackContext).bind();
-        actionContext.setServletRequest(request);
+        actionContext.withServletRequest(request);
     }
 
     protected static String s(String input) {
diff --git a/plugins/jfreechart/src/test/java/org/apache/struts2/dispatcher/ChartResultTest.java b/plugins/jfreechart/src/test/java/org/apache/struts2/dispatcher/ChartResultTest.java
index b05496d..0dda173 100644
--- a/plugins/jfreechart/src/test/java/org/apache/struts2/dispatcher/ChartResultTest.java
+++ b/plugins/jfreechart/src/test/java/org/apache/struts2/dispatcher/ChartResultTest.java
@@ -153,8 +153,6 @@ public class ChartResultTest extends StrutsTestCase {
 
 
         stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
-
 
         mockActionProxy = EasyMock.createNiceMock(ActionProxy.class);
         EasyMock.expect(mockActionProxy.getNamespace()).andReturn("/html");
diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java
index 134c6fb..48cfcb5 100644
--- a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java
+++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java
@@ -22,7 +22,6 @@ import java.util.Calendar;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.StrutsTestCase;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
@@ -517,15 +516,15 @@ public class JSONInterceptorTest extends StrutsTestCase {
         this.request = new MockHttpServletRequest();
         this.response = new MockHttpServletResponse();
 
-        ActionContext context = ActionContext.getContext();
-        ValueStack stack = context.getValueStack();
+        MockServletContext servletContext = new MockServletContext();
 
-        context.setServletRequest(request);
-        context.setServletResponse(response);
+        ActionContext context = ActionContext.getContext()
+            .withServletRequest(request)
+            .withServletResponse(response)
+            .withServletContext(servletContext);
 
-        MockServletContext servletContext = new MockServletContext();
+        ValueStack stack = context.getValueStack();
 
-        context.setServletContext(servletContext);
         this.invocation = new MockActionInvocationEx();
         this.invocation.setInvocationContext(context);
         this.invocation.setStack(stack);
diff --git a/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java b/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java
index 75ce279..634cc0a 100644
--- a/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java
+++ b/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java
@@ -143,7 +143,7 @@ public abstract class StrutsJUnit4TestCase<T> extends XWorkJUnit4TestCase {
 
     protected void initSession(ActionContext actionContext) {
         if (actionContext.getSession() == null) {
-            actionContext.setSession(new HashMap<String, Object>());
+            actionContext.withSession(new HashMap<>());
             request.setSession(new MockHttpSession(servletContext));
         }
     }
diff --git a/plugins/junit/src/main/java/org/apache/struts2/StrutsPortletTestCase.java b/plugins/junit/src/main/java/org/apache/struts2/StrutsPortletTestCase.java
index 624a186..b5b4309 100644
--- a/plugins/junit/src/main/java/org/apache/struts2/StrutsPortletTestCase.java
+++ b/plugins/junit/src/main/java/org/apache/struts2/StrutsPortletTestCase.java
@@ -71,7 +71,7 @@ public abstract class StrutsPortletTestCase extends StrutsTestCase {
         portletResponse = new MockStateAwareResponse();
         portletSession = new MockPortletSession();
         portletRequest.setSession(portletSession);
-        actionContext.setSession(createSession());
+        actionContext.withSession(createSession());
         actionContext.put(PortletConstants.REQUEST, portletRequest);
         actionContext.put(PortletConstants.RESPONSE, portletResponse);
         actionContext.put(PortletConstants.MODE_NAMESPACE_MAP, new HashMap<PortletMode, String>());
diff --git a/plugins/junit/src/main/java/org/apache/struts2/StrutsTestCase.java b/plugins/junit/src/main/java/org/apache/struts2/StrutsTestCase.java
index 808ef63..8451515 100644
--- a/plugins/junit/src/main/java/org/apache/struts2/StrutsTestCase.java
+++ b/plugins/junit/src/main/java/org/apache/struts2/StrutsTestCase.java
@@ -127,7 +127,7 @@ public abstract class StrutsTestCase extends XWorkTestCase {
 
     protected void initSession(ActionContext actionContext) {
         if (actionContext.getSession() == null) {
-            actionContext.setSession(new HashMap<String, Object>());
+            actionContext.withSession(new HashMap<>());
             request.setSession(new MockHttpSession(servletContext));
         }
     }
diff --git a/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java
index 9016145..fcae67c 100644
--- a/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java
+++ b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java
@@ -159,11 +159,11 @@ public class PortletVelocityResult extends StrutsResultSupport {
         velocityManager.init(servletContext);
 
         boolean usedJspFactory = false;
-        PageContext pageContext = (PageContext) ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT);
+        PageContext pageContext = ActionContext.getContext().getPageContext();
 
         if (pageContext == null && servlet != null) {
             pageContext = jspFactory.getPageContext(servlet, request, response, null, true, 8192, true);
-            ActionContext.getContext().put(ServletActionContext.PAGE_CONTEXT, pageContext);
+            ActionContext.getContext().withPageContext(pageContext);
             usedJspFactory = true;
         }
 
diff --git a/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java b/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java
index 26c4400..a1e5598 100644
--- a/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java
+++ b/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java
@@ -153,12 +153,13 @@ public class PortletUrlTagTest extends MockObjectTestCase {
         contextMap.put(PortletConstants.DEFAULT_ACTION_MAP, actionMap);
         contextMap.put(STRUTS_PORTLET_CONTEXT, mockCtx.proxy());
 
-        ActionContext ctx = ActionContext.of(contextMap).bind();
-        ctx.setValueStack(stack);
-        ctx.setContainer(dispatcher.getContainer());
-
         ActionInvocation ai = (ActionInvocation) mockActionInvocation.proxy();
-        ctx.setActionInvocation(ai);
+
+        ActionContext.of(contextMap)
+            .withValueStack(stack)
+            .withContainer(dispatcher.getContainer())
+            .withActionInvocation(ai)
+            .bind();
     }
 
     public void tearDown() throws Exception {
diff --git a/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java b/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java
index a55d0d2..3e2a41e 100644
--- a/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java
+++ b/plugins/rest/src/test/java/org/apache/struts2/rest/ContentTypeHandlerManagerTest.java
@@ -59,8 +59,8 @@ public class ContentTypeHandlerManagerTest extends TestCase {
         mockRequest = new MockHttpServletRequest();
         mockRequest.setMethod("GET");
         ActionContext actionContext = ActionContext.of(new HashMap<>()).bind();
-        actionContext.setServletRequest(mockRequest);
-        actionContext.setServletResponse(mockResponse);
+        actionContext.withServletRequest(mockRequest);
+        actionContext.withServletResponse(mockResponse);
 
         invocation = new MockActionInvocation();
         invocation.setProxy(new MockActionProxy());
diff --git a/plugins/rest/src/test/java/org/apache/struts2/rest/RestWorkflowInterceptorTest.java b/plugins/rest/src/test/java/org/apache/struts2/rest/RestWorkflowInterceptorTest.java
index d3b9541..45d82e4 100644
--- a/plugins/rest/src/test/java/org/apache/struts2/rest/RestWorkflowInterceptorTest.java
+++ b/plugins/rest/src/test/java/org/apache/struts2/rest/RestWorkflowInterceptorTest.java
@@ -51,8 +51,9 @@ public class RestWorkflowInterceptorTest extends TestCase {
         }, null);
         wf.setContentTypeHandlerManager((ContentTypeHandlerManager) mockContentTypeHandlerManager.proxy());
 
-        ActionContext actionContext = ActionContext.of(new HashMap<>()).bind();
-        actionContext.setActionMapping(new ActionMapping());
+        ActionContext.of(new HashMap<>())
+            .withActionMapping(new ActionMapping())
+            .bind();
 
         wf.doIntercept((ActionInvocation) mockActionInvocation.proxy());
         mockContentTypeHandlerManager.verify();
diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java
index c62f687..68b5645 100644
--- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java
+++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/result/VelocityResult.java
@@ -128,11 +128,11 @@ public class VelocityResult extends StrutsResultSupport {
         velocityManager.init(servletContext);
 
         boolean usedJspFactory = false;
-        PageContext pageContext = (PageContext) ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT);
+        PageContext pageContext = (PageContext) ActionContext.getContext().getPageContext();
 
         if (pageContext == null && servlet != null) {
             pageContext = jspFactory.getPageContext(servlet, request, response, null, true, 8192, true);
-            ActionContext.getContext().put(ServletActionContext.PAGE_CONTEXT, pageContext);
+            ActionContext.getContext().withPageContext(pageContext);
             usedJspFactory = true;
         }
 
diff --git a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/result/VelocityResultTest.java b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/result/VelocityResultTest.java
index 7fa4bb9..b027e92 100644
--- a/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/result/VelocityResultTest.java
+++ b/plugins/velocity/src/test/java/org/apache/struts2/views/velocity/result/VelocityResultTest.java
@@ -93,7 +93,6 @@ public class VelocityResultTest extends XWorkTestCase {
         namespace = "/html";
         result = new VelocityResult();
         stack = ActionContext.getContext().getValueStack();
-        ActionContext.getContext().setValueStack(stack);
         velocity = new TestVelocityEngine();
         mockActionProxy = new Mock(ActionProxy.class);
         mockActionProxy.expectAndReturn("getNamespace", "/html");