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:11 UTC

[struts] branch action-context-boost updated (f22eac7 -> dfda16d)

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

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


 discard f22eac7  WW-4789 WW-3788 Introduces helper methods to allow build fluent API
     new dfda16d  WW-4789 WW-3788 Introduces helper methods to allow build fluent API

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (f22eac7)
            \
             N -- N -- N   refs/heads/action-context-boost (dfda16d)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../com/opensymphony/xwork2/ActionContext.java     | 33 +++++++--
 .../apache/struts2/dispatcher/HttpParameters.java  |  1 +
 .../com/opensymphony/xwork2/ActionContextTest.java | 18 ++---
 .../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       |  2 +-
 .../validator/validators/ValidatorSupportTest.java | 43 +++++-------
 .../apache/struts2/components/UIComponentTest.java |  1 -
 .../interceptor/ServletConfigInterceptorTest.java  |  6 +-
 .../StrutsConversionErrorInterceptorTest.java      |  5 +-
 .../struts2/util/InvocationSessionStoreTest.java   | 37 +++++-----
 .../org/apache/struts2/views/jsp/I18nTagTest.java  |  1 -
 .../org/apache/struts2/views/jsp/IfTagTest.java    |  1 -
 .../apache/struts2/views/jsp/ui/FormTagTest.java   |  2 -
 .../org/apache/struts2/EmbeddedJSPResultTest.java  | 17 +++--
 .../apache/struts2/dispatcher/ChartResultTest.java |  2 -
 .../portlet/result/PortletVelocityResult.java      |  4 +-
 .../struts2/views/jsp/PortletUrlTagTest.java       | 11 +--
 .../struts2/rest/RestWorkflowInterceptorTest.java  |  5 +-
 .../views/velocity/result/VelocityResult.java      |  4 +-
 .../views/velocity/result/VelocityResultTest.java  |  1 -
 27 files changed, 167 insertions(+), 198 deletions(-)


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

Posted by lu...@apache.org.
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");