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 2022/01/04 08:01:28 UTC

[struts] 01/01: WW-5022 Sets escapeHtmlBody to false by default and defines new flag to switch to true globally

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

lukaszlenart pushed a commit to branch WW-5022-escape-false
in repository https://gitbox.apache.org/repos/asf/struts.git

commit ecef56b546b1a7ae3a8411b3e2af2b64fc72799e
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Tue Jan 4 09:01:21 2022 +0100

    WW-5022 Sets escapeHtmlBody to false by default and defines new flag to switch to true globally
---
 core/pom.xml                                       |   2 +-
 .../java/org/apache/struts2/StrutsConstants.java   |  14 ++-
 .../java/org/apache/struts2/components/Anchor.java |  18 +--
 .../org/apache/struts2/components/Component.java   |  22 ++--
 .../java/org/apache/struts2/components/Submit.java |  18 +--
 .../org/apache/struts2/views/jsp/ui/AnchorTag.java |  18 +--
 .../org/apache/struts2/views/jsp/ui/SubmitTag.java |   8 +-
 .../apache/struts2/components/ComponentTest.java   | 133 ++++++++-------------
 .../apache/struts2/views/jsp/ui/AnchorTest.java    |  48 +++++---
 .../apache/struts2/views/jsp/ui/CheckboxTest.java  |   4 +-
 .../org/apache/struts2/views/jsp/ui/FileTest.java  |   4 +-
 .../apache/struts2/views/jsp/ui/SubmitTest.java    |   9 +-
 .../apache/struts2/views/jsp/ui/TextareaTest.java  |   4 +-
 core/src/test/resources/struts-escape-body.xml     |  31 +++++
 14 files changed, 168 insertions(+), 165 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index 9807142..cd56777 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -342,7 +342,7 @@
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-simple</artifactId>
-            <optional>true</optional>
+            <scope>test</scope>
         </dependency>
 
         <!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index 60007ce..626f963 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -35,13 +35,13 @@ public final class StrutsConstants {
     /** The encoding to use for localization messages */
     public static final String STRUTS_I18N_ENCODING = "struts.i18n.encoding";
 
-    /** 
+    /**
      * Whether the default bundles should be searched for messages first.  Can be used to modify the
      * standard processing order for message lookup in TextProvider implementations.
      * <p>
      * Note: This control flag may not be meaningful to all provider implementations, and should be false by default.
      * </p>
-     * 
+     *
      * @since 2.6
      */
     public static final String STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST = "struts.i18n.search.defaultbundles.first";
@@ -104,10 +104,10 @@ public final class StrutsConstants {
 
     /** Update freemarker templates cache in seconds */
     public static final String STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY = "struts.freemarker.templatesCache.updateDelay";
-    
+
     /** Cache model instances at BeanWrapper level */
     public static final String STRUTS_FREEMARKER_BEANWRAPPER_CACHE = "struts.freemarker.beanwrapperCache";
-    
+
     /** Maximum strong sizing for MruCacheStorage for freemarker */
     public static final String STRUTS_FREEMARKER_MRU_MAX_STRONG_SIZE = "struts.freemarker.mru.max.strong.size";
 
@@ -132,6 +132,9 @@ public final class StrutsConstants {
     /** A path to static content, by default and from historical point of view it's /static. */
     public static final String STRUTS_UI_STATIC_CONTENT_PATH = "struts.ui.staticContentPath";
 
+    /** A global flag to enable/disable html body escaping in tags, can be overwritten per tag */
+    public static final String STRUTS_UI_ESCAPE_HTML_BODY = "struts.ui.escapeHtmlBody";
+
     /** The maximize size of a multipart request (file upload) */
     public static final String STRUTS_MULTIPART_MAXSIZE = "struts.multipart.maxSize";
 
@@ -188,7 +191,7 @@ public final class StrutsConstants {
      * You can specify different prefixes that will be handled by different mappers
      */
     public static final String PREFIX_BASED_MAPPER_CONFIGURATION = "struts.mapper.prefixMapping";
-    
+
     /** Whether the Struts filter should serve static content or not */
     public static final String STRUTS_SERVE_STATIC_CONTENT = "struts.serve.static";
 
@@ -362,4 +365,5 @@ public final class StrutsConstants {
     public static final String STRUTS_CHAINING_COPY_FIELD_ERRORS = "struts.chaining.copyFieldErrors";
     public static final String STRUTS_CHAINING_COPY_MESSAGES = "struts.chaining.copyMessages";
     public static final String STRUTS_OBJECT_FACTORY_CLASSLOADER = "struts.objectFactory.classloader";
+
 }
diff --git a/core/src/main/java/org/apache/struts2/components/Anchor.java b/core/src/main/java/org/apache/struts2/components/Anchor.java
index 153fdf8..e00291d 100644
--- a/core/src/main/java/org/apache/struts2/components/Anchor.java
+++ b/core/src/main/java/org/apache/struts2/components/Anchor.java
@@ -20,6 +20,7 @@ package org.apache.struts2.components;
 
 import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.util.ValueStack;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -69,8 +70,7 @@ public class Anchor extends ClosingUIBean {
     protected UrlProvider urlProvider;
     protected UrlRenderer urlRenderer;
     protected boolean processingTagBody = false;
-    protected boolean escapeHtmlBody = true;
-    
+
     //these params are passed by the Param tag
     protected Map urlParameters = new LinkedHashMap();
 
@@ -96,18 +96,6 @@ public class Anchor extends ClosingUIBean {
         return true;
     }
 
-    /**
-     * Override to set if body content should be HTML-escaped.
-     * 
-     * @return true if body should be HTML-escaped, false otherwise.
-     * 
-     * @since 2.6
-     */
-    @Override
-    public boolean escapeHtmlBody() {
-        return escapeHtmlBody;
-    }
-
     @Override
     protected void evaluateExtraParams() {
         super.evaluateExtraParams();
@@ -276,7 +264,7 @@ public class Anchor extends ClosingUIBean {
         urlProvider.setForceAddSchemeHostAndPort(forceAddSchemeHostAndPort);
     }
 
-    @StrutsTagAttribute(required = false, description = "Specifies whether to HTML-escape the tag body or not", type = "Boolean", defaultValue = "true")
+    @StrutsTagAttribute(description = "Specifies whether to HTML-escape the tag body or not", type = "Boolean", defaultValue = "true")
     public void setEscapeHtmlBody(boolean escapeHtmlBody) {
         this.escapeHtmlBody = escapeHtmlBody;
     }
diff --git a/core/src/main/java/org/apache/struts2/components/Component.java b/core/src/main/java/org/apache/struts2/components/Component.java
index 4d5c845..2b0c58a 100644
--- a/core/src/main/java/org/apache/struts2/components/Component.java
+++ b/core/src/main/java/org/apache/struts2/components/Component.java
@@ -68,6 +68,7 @@ public class Component {
     protected static ConcurrentMap<Class<?>, Collection<String>> standardAttributesMap = new ConcurrentHashMap<>();
 
     protected boolean devMode = false;
+    protected boolean escapeHtmlBody = false;
     protected ValueStack stack;
     protected Map<String, Object> parameters;
     protected ActionMapper actionMapper;
@@ -116,6 +117,11 @@ public class Component {
         this.throwExceptionOnELFailure = BooleanUtils.toBoolean(throwException);
     }
 
+    @Inject(value = StrutsConstants.STRUTS_UI_ESCAPE_HTML_BODY, required = false)
+    public void setEscapeHtmlBody(String escapeHtmlBody) {
+        this.escapeHtmlBody = BooleanUtils.toBoolean(escapeHtmlBody);
+    }
+
     @Inject
     public void setUrlHelper(UrlHelper urlHelper) {
         this.urlHelper = urlHelper;
@@ -213,13 +219,13 @@ public class Component {
      * @return the component if found, <tt>null</tt> if not.
      */
     protected Component findAncestor(Class<?> clazz) {
-        Stack componentStack = getComponentStack();
+        Stack<Component> componentStack = getComponentStack();
         int currPosition = componentStack.search(this);
         if (currPosition >= 0) {
             int start = componentStack.size() - currPosition - 1;
 
             for (int i = start; i >= 0; i--) {
-                Component component = (Component) componentStack.get(i);
+                Component component = componentStack.get(i);
                 if (clazz.isAssignableFrom(component.getClass()) && component != this) {
                     return component;
                 }
@@ -536,7 +542,7 @@ public class Component {
      * @since 2.6
      */
     public boolean escapeHtmlBody() {
-        return true;
+        return escapeHtmlBody;
     }
 
     /**
@@ -572,16 +578,16 @@ public class Component {
     /**
      * Request that the tag state be cleared during {@link org.apache.struts2.views.jsp.StrutsBodyTagSupport#doEndTag()} processing,
      * which may help with certain edge cases with tag logic running on servers that implement JSP Tag Pooling.
-     * 
-     * <em>Note:</em> All Tag classes that extend {@link org.apache.struts2.views.jsp.StrutsBodyTagSupport} must implement a setter for 
+     *
+     * <em>Note:</em> All Tag classes that extend {@link org.apache.struts2.views.jsp.StrutsBodyTagSupport} must implement a setter for
      * this attribute (same name), and it must be defined at the Tag class level.
      * Defining a setter in the superclass alone is insufficient (results in "Cannot find a setter method for the attribute").
-     * 
+     *
      * See {@link org.apache.struts2.views.jsp.StrutsBodyTagSupport#clearTagStateForTagPoolingServers()  for additional details.
-     * 
+     *
      * @param performClearTagStateForTagPoolingServers true if tag state should be cleared, false otherwise.
      */
-    @StrutsTagAttribute(description="Whether to clear all tag state during doEndTag() processing (if applicable)", type="Boolean", defaultValue="false", required = false)
+    @StrutsTagAttribute(description="Whether to clear all tag state during doEndTag() processing (if applicable)", type="Boolean", defaultValue="false")
     public void setPerformClearTagStateForTagPoolingServers(boolean performClearTagStateForTagPoolingServers) {
         this.performClearTagStateForTagPoolingServers = performClearTagStateForTagPoolingServers;
     }
diff --git a/core/src/main/java/org/apache/struts2/components/Submit.java b/core/src/main/java/org/apache/struts2/components/Submit.java
index 124526a..6a9ce97 100644
--- a/core/src/main/java/org/apache/struts2/components/Submit.java
+++ b/core/src/main/java/org/apache/struts2/components/Submit.java
@@ -23,6 +23,9 @@ import java.io.Writer;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import com.opensymphony.xwork2.inject.Inject;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.views.annotations.StrutsTag;
 import org.apache.struts2.views.annotations.StrutsTagAttribute;
 
@@ -54,7 +57,6 @@ public class Submit extends FormButton {
     final public static String OPEN_TEMPLATE = "submit";
     final public static String TEMPLATE = "submit-close";
     protected String src;
-    protected boolean escapeHtmlBody = true;
 
     public Submit(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
         super(stack, request, response);
@@ -101,7 +103,7 @@ public class Submit extends FormButton {
         this.src = src;
     }
 
-    @StrutsTagAttribute(required = false, description = "Specifies whether to HTML-escape the tag body or not", type = "Boolean", defaultValue = "true")
+    @StrutsTagAttribute(description = "Specifies whether to HTML-escape the tag body or not", type = "Boolean", defaultValue = "true")
     public void setEscapeHtmlBody(boolean escapeHtmlBody) {
         this.escapeHtmlBody = escapeHtmlBody;
     }
@@ -112,18 +114,6 @@ public class Submit extends FormButton {
     }
 
     /**
-     * Override to set if body content should be HTML-escaped.
-     * 
-     * @return true if body should be HTML-escaped, false otherwise.
-     * 
-     * @since 2.6
-     */
-    @Override
-    public boolean escapeHtmlBody() {
-        return escapeHtmlBody;
-    }
-
-    /**
      * Overrides to be able to render body in a template rather than always before the template
      */
     public boolean end(Writer writer, String body) {
diff --git a/core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java b/core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java
index 4f334ad..0e181d5 100644
--- a/core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java
+++ b/core/src/main/java/org/apache/struts2/views/jsp/ui/AnchorTag.java
@@ -47,13 +47,13 @@ public class AnchorTag extends AbstractClosingTag {
     protected String portletUrlType;
     protected String anchor;
     protected String forceAddSchemeHostAndPort;
-    protected boolean escapeHtmlBody = true;  // Default - escape HTML body
+    protected String escapeHtmlBody;
 
     @Override
     public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
         return new Anchor(stack, req, res);
     }
-    
+
     @Override
     protected void populateParams() {
         super.populateParams();
@@ -80,10 +80,12 @@ public class AnchorTag extends AbstractClosingTag {
         if (escapeAmp != null) {
             tag.setEscapeAmp(BooleanUtils.toBoolean(escapeAmp));
         }
-	if (forceAddSchemeHostAndPort != null) {
+        if (forceAddSchemeHostAndPort != null) {
             tag.setForceAddSchemeHostAndPort(BooleanUtils.toBoolean(forceAddSchemeHostAndPort));
         }
-        tag.setEscapeHtmlBody(escapeHtmlBody);
+        if (escapeHtmlBody != null) {
+            tag.setEscapeHtmlBody(escapeHtmlBody);
+        }
     }
 
     public void setHref(String href) {
@@ -149,12 +151,12 @@ public class AnchorTag extends AbstractClosingTag {
 
     /**
      * Set via parameter to control if body content should be HTML-escaped.
-     * 
-     * @param escapeHtmlBody 
-     * 
+     *
+     * @param escapeHtmlBody
+     *
      * @since 2.6
      */
-    public void setEscapeHtmlBody(boolean escapeHtmlBody) {
+    public void setEscapeHtmlBody(String escapeHtmlBody) {
         this.escapeHtmlBody = escapeHtmlBody;
     }
 
diff --git a/core/src/main/java/org/apache/struts2/views/jsp/ui/SubmitTag.java b/core/src/main/java/org/apache/struts2/views/jsp/ui/SubmitTag.java
index 5250cbe..2bfd6a9 100644
--- a/core/src/main/java/org/apache/struts2/views/jsp/ui/SubmitTag.java
+++ b/core/src/main/java/org/apache/struts2/views/jsp/ui/SubmitTag.java
@@ -37,7 +37,7 @@ public class SubmitTag extends AbstractClosingTag {
     protected String method;
     protected String type;
     protected String src;
-    protected boolean escapeHtmlBody = true;  // Default - escape HTML body
+    protected boolean escapeHtmlBody = false;
 
     @Override
     public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
@@ -78,9 +78,9 @@ public class SubmitTag extends AbstractClosingTag {
 
     /**
      * Set via parameter to control if body content should be HTML-escaped.
-     * 
-     * @param escapeHtmlBody 
-     * 
+     *
+     * @param escapeHtmlBody
+     *
      * @since 2.6
      */
     public void setEscapeHtmlBody(boolean escapeHtmlBody) {
diff --git a/core/src/test/java/org/apache/struts2/components/ComponentTest.java b/core/src/test/java/org/apache/struts2/components/ComponentTest.java
index 0bc0982..762e37a 100644
--- a/core/src/test/java/org/apache/struts2/components/ComponentTest.java
+++ b/core/src/test/java/org/apache/struts2/components/ComponentTest.java
@@ -18,14 +18,11 @@
  */
 package org.apache.struts2.components;
 
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Stack;
-
-import javax.servlet.jsp.tagext.TagSupport;
-
 import com.opensymphony.xwork2.LocalizedTextProvider;
+import org.apache.struts2.StrutsException;
+import org.apache.struts2.TestConfigurationProvider;
 import org.apache.struts2.views.jsp.AbstractTagTest;
+import org.apache.struts2.views.jsp.ActionTag;
 import org.apache.struts2.views.jsp.BeanTag;
 import org.apache.struts2.views.jsp.ElseIfTag;
 import org.apache.struts2.views.jsp.ElseTag;
@@ -42,17 +39,19 @@ import org.apache.struts2.views.jsp.iterator.MergeIteratorTag;
 import org.apache.struts2.views.jsp.ui.TextFieldTag;
 import org.apache.struts2.views.jsp.ui.UpDownSelectTag;
 
+import javax.servlet.jsp.tagext.TagSupport;
 import java.util.HashMap;
-import org.apache.struts2.StrutsException;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Stack;
 
 /**
  * Test case for method findAncestor(Class) in Component and some commons
  * test cases for Component in general.
- *
  */
 public class ComponentTest extends AbstractTagTest {
 
-    public void testFindAncestorTest() throws Exception {
+    public void testFindAncestorTest() {
         Property property = new Property(stack);
         Form form = new Form(stack, request, response);
         ActionComponent actionComponent = new ActionComponent(stack, request, response);
@@ -61,8 +60,8 @@ public class ComponentTest extends AbstractTagTest {
         TextField textField = new TextField(stack, request, response);
 
 
-        Stack stack = property.getComponentStack();
-        Iterator i = stack.iterator();
+        Stack<Component> stack = property.getComponentStack();
+        Iterator<Component> i = stack.iterator();
 
 
         try {
@@ -107,8 +106,7 @@ public class ComponentTest extends AbstractTagTest {
             assertEquals(textField.findAncestor(Anchor.class), anchor);
             assertEquals(textField.findAncestor(ActionComponent.class), actionComponent);
             assertEquals(textField.findAncestor(Property.class), property);
-        }
-        finally {
+        } finally {
             property.getComponentStack().pop();
             property.getComponentStack().pop();
             property.getComponentStack().pop();
@@ -118,16 +116,7 @@ public class ComponentTest extends AbstractTagTest {
     }
 
     // Action Component
-    /*
-    public void testActionComponentDisposeItselfFromComponentStack() throws Exception {
-        ConfigurationManager.clearConfigurationProviders();
-        ConfigurationManager.addConfigurationProvider(new TestConfigurationProvider());
-        ConfigurationManager.getConfiguration().reload();
-
-        ActionContext actionContext = new ActionContext(context);
-        actionContext.setValueStack(stack);
-        ActionContext.setContext(actionContext);
-
+    public void testActionComponentDisposeItselfFromComponentStack() {
         request.setupGetServletPath(TestConfigurationProvider.TEST_NAMESPACE + "/" + "foo.action");
         try {
             TextFieldTag t = new TextFieldTag();
@@ -145,17 +134,14 @@ public class ComponentTest extends AbstractTagTest {
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
 
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
     }
-    */
-
 
     // AppendInterator
-    public void testAppendIteratorDisposeItselfFromComponentStack() throws Exception {
+    public void testAppendIteratorDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -170,8 +156,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -179,7 +164,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Bean
-    public void testBeanComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testBeanComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -195,8 +180,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail();
         }
@@ -204,7 +188,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // ElseIf
-    public void testElseIfComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testElseIfComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -219,8 +203,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -228,7 +211,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Else
-    public void testElseComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testElseComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -243,8 +226,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -252,7 +234,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // If
-    public void testIfComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testIfComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -268,8 +250,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -277,7 +258,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Iterator
-    public void testIteratorComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testIteratorComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -291,15 +272,14 @@ public class ComponentTest extends AbstractTagTest {
             tag.doStartTag();
             assertEquals(tag.getComponent().getComponentStack().peek(), tag.getComponent());
             int endIt = tag.doAfterBody();
-            while(TagSupport.EVAL_BODY_AGAIN == endIt) {
+            while (TagSupport.EVAL_BODY_AGAIN == endIt) {
                 assertEquals(tag.getComponent().getComponentStack().peek(), tag.getComponent());
                 endIt = tag.doAfterBody();
             }
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -307,7 +287,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // MergeIterator
-    public void testMergeIteratorComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testMergeIteratorComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -322,8 +302,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -331,7 +310,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Property
-    public void testPropertyComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testPropertyComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -346,8 +325,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -355,7 +333,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Push
-    public void testPushComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testPushComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -371,8 +349,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -380,7 +357,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Set
-    public void testSetComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testSetComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -397,8 +374,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -406,7 +382,7 @@ public class ComponentTest extends AbstractTagTest {
 
 
     // Text
-    public void testTextComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testTextComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -422,15 +398,14 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
     }
 
 
-    public void testI18nComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testI18nComponentDisposeItselfFromComponentStack() {
         stack.getActionContext().withLocale(Locale.getDefault());
 
         TextFieldTag t = new TextFieldTag();
@@ -450,15 +425,14 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
     }
 
     // URL
-    public void testURLComponentDisposeItselfFromComponentStack() throws Exception {
+    public void testURLComponentDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -473,15 +447,14 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
     }
 
     // updownselect
-    public void testUpDownSelectDisposeItselfFromComponentStack() throws Exception {
+    public void testUpDownSelectDisposeItselfFromComponentStack() {
         TextFieldTag t = new TextFieldTag();
         t.setPageContext(pageContext);
         t.setName("textFieldName");
@@ -499,8 +472,7 @@ public class ComponentTest extends AbstractTagTest {
             tag.doEndTag();
             assertEquals(t.getComponent().getComponentStack().peek(), t.getComponent());
             t.doEndTag();
-        }
-        catch(Exception e) {
+        } catch (Exception e) {
             e.printStackTrace();
             fail(e.toString());
         }
@@ -508,22 +480,22 @@ public class ComponentTest extends AbstractTagTest {
 
     /**
      * Test the expected default behaviour for component body state methods.
-      */
+     */
     public void testComponentDefaultBodyStates() {
         Component component = new Component(stack);
         // Test expected default results for: usesBody(), escapeHtmlBody().
         assertFalse("Component default usesBody not false ?", component.usesBody());
-        assertTrue("Component default htmlEscapeBody not true ?", component.escapeHtmlBody());
+        assertFalse("Component default htmlEscapeBody not false ?", component.escapeHtmlBody());
     }
 
     /**
      * Test the behaviour for Anchor body state methods.
-      */
+     */
     public void testAnchorBodyStates() {
         Anchor anchor = new Anchor(stack, request, response);
         // Test expected default results for: usesBody(), escapeHtmlBody().
         assertTrue("Anchor default usesBody not true ?", anchor.usesBody());
-        assertTrue("Anchor default htmlEscapeBody not true ?", anchor.escapeHtmlBody());
+        assertFalse("Anchor default htmlEscapeBody not false ?", anchor.escapeHtmlBody());
         anchor.setEscapeHtmlBody(false);
         assertFalse("Anchor htmlEscapeBody not false after set false ?", anchor.escapeHtmlBody());
         anchor.setEscapeHtmlBody(true);
@@ -532,12 +504,12 @@ public class ComponentTest extends AbstractTagTest {
 
     /**
      * Test the behaviour for Submit body state methods.
-      */
-    public void testAnchortBodyStates() {
+     */
+    public void testSubmitBodyStates() {
         Submit submit = new Submit(stack, request, response);
         // Test expected default results for: usesBody(), escapeHtmlBody().
         assertTrue("Submit default usesBody not true ?", submit.usesBody());
-        assertTrue("Submit default htmlEscapeBody not true ?", submit.escapeHtmlBody());
+        assertFalse("Submit default htmlEscapeBody not false ?", submit.escapeHtmlBody());
         submit.setEscapeHtmlBody(false);
         assertFalse("Submit htmlEscapeBody not false after set false ?", submit.escapeHtmlBody());
         submit.setEscapeHtmlBody(true);
@@ -547,10 +519,8 @@ public class ComponentTest extends AbstractTagTest {
     /**
      * Attempt some code coverage tests for {@link Component} that can be achieved without
      * too much difficulty.
-     * 
-     * @throws Exception 
      */
-    public void testComponent_coverageTest() throws Exception {
+    public void testComponent_coverageTest() {
         HashMap<String, Object> propertyMap = new HashMap<>();
         Exception exception = new Exception("Generic exception");
         Property property = new Property(stack);
@@ -586,8 +556,7 @@ public class ComponentTest extends AbstractTagTest {
             assertFalse("Initial performClearTagStateForTagPoolingServers not false ?", actionComponent.getPerformClearTagStateForTagPoolingServers());
             actionComponent.setPerformClearTagStateForTagPoolingServers(true);
             assertTrue("performClearTagStateForTagPoolingServers false after setting to true ?", actionComponent.getPerformClearTagStateForTagPoolingServers());
-        }
-        finally {
+        } finally {
             property.getComponentStack().pop();
         }
     }
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java
index 8101cc8..53fa8ba 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/AnchorTest.java
@@ -18,17 +18,15 @@
  */
 package org.apache.struts2.views.jsp.ui;
 
+import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.TestAction;
+import org.apache.struts2.components.Anchor;
 import org.apache.struts2.views.jsp.AbstractUITagTest;
 
-import javax.servlet.jsp.JspException;
 import java.beans.BeanInfo;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 
-
-/**
- */
 public class AnchorTest extends AbstractUITagTest {
 
     public void testBeanInfo() throws Exception {
@@ -72,7 +70,7 @@ public class AnchorTest extends AbstractUITagTest {
         AnchorTag freshTag = new AnchorTag();
         freshTag.setPerformClearTagStateForTagPoolingServers(true);
         freshTag.setPageContext(pageContext);
-        assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set.  " +
+        assertTrue("Tag state after doEndTag() and explicit tag state clearing is unequal to new Tag with pageContext/parent set.  " +
                 "May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
                 strutsBodyTagsAreReflectionEqual(tag, freshTag));
     }
@@ -111,7 +109,7 @@ public class AnchorTest extends AbstractUITagTest {
         AnchorTag freshTag = new AnchorTag();
         freshTag.setPerformClearTagStateForTagPoolingServers(true);
         freshTag.setPageContext(pageContext);
-        assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set.  " +
+        assertTrue("Tag state after doEndTag() and explicit tag state clearing is unequal to new Tag with pageContext/parent set.  " +
                 "May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
                 strutsBodyTagsAreReflectionEqual(tag, freshTag));
     }
@@ -156,7 +154,7 @@ public class AnchorTest extends AbstractUITagTest {
         AnchorTag freshTag = new AnchorTag();
         freshTag.setPerformClearTagStateForTagPoolingServers(true);
         freshTag.setPageContext(pageContext);
-        assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set.  " +
+        assertTrue("Tag state after doEndTag() and explicit tag state clearing is unequal to new Tag with pageContext/parent set.  " +
                 "May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
                 strutsBodyTagsAreReflectionEqual(tag, freshTag));
     }
@@ -201,7 +199,7 @@ public class AnchorTest extends AbstractUITagTest {
         AnchorTag freshTag = new AnchorTag();
         freshTag.setPerformClearTagStateForTagPoolingServers(true);
         freshTag.setPageContext(pageContext);
-        assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set.  " +
+        assertTrue("Tag state after doEndTag() and explicit tag state clearing is unequal to new Tag with pageContext/parent set.  " +
                 "May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
                 strutsBodyTagsAreReflectionEqual(tag, freshTag));
     }
@@ -211,7 +209,7 @@ public class AnchorTest extends AbstractUITagTest {
         testAction.setFoo("bar");
     }
 
-    private AnchorTag createTag() throws JspException {
+    private AnchorTag createTag() {
         AnchorTag tag = new AnchorTag();
         tag.setPageContext(pageContext);
 
@@ -221,8 +219,6 @@ public class AnchorTest extends AbstractUITagTest {
 
     /**
      * Test anchor tag body supported
-     * 
-     * @throws Exception 
      */
     public void testSimpleWithBody() throws Exception {
         createAction();
@@ -242,8 +238,6 @@ public class AnchorTest extends AbstractUITagTest {
 
     /**
      * Test that by default anchor tag body is HTML-escaped.
-     * 
-     * @throws Exception 
      */
     public void testSimpleWithBodyHTMLEscaped() throws Exception {
         createAction();
@@ -254,6 +248,7 @@ public class AnchorTest extends AbstractUITagTest {
         StrutsBodyContent body = new StrutsBodyContent(null);
         body.print("should HTML escape: < & >");
         tag.setBodyContent(body);
+        tag.setEscapeHtmlBody("true");
 
         tag.doStartTag();
         tag.doEndTag();
@@ -263,15 +258,13 @@ public class AnchorTest extends AbstractUITagTest {
 
     /**
      * Test that with htmlEscapeBody false anchor tag body is not HTML-escaped.
-     * 
-     * @throws Exception 
      */
     public void testSimpleWithBodyNotHTMLEscaped() throws Exception {
         createAction();
 
         AnchorTag tag = createTag();
         tag.setHref("a");
-        tag.setEscapeHtmlBody(false);
+        tag.setEscapeHtmlBody("false");
 
         StrutsBodyContent body = new StrutsBodyContent(null);
         body.print("should not HTML escape: < & >");
@@ -282,4 +275,27 @@ public class AnchorTest extends AbstractUITagTest {
 
         verifyResource("href-5.txt");
     }
+
+    public void testInjectEscapeHtmlBodyFlag() throws Exception {
+        // given
+        initDispatcherWithConfigs("struts-default.xml, struts-escape-body.xml");
+        String escapeHtmlBody = container.getInstance(String.class, StrutsConstants.STRUTS_UI_ESCAPE_HTML_BODY);
+        assertEquals("true", escapeHtmlBody);
+
+        createMocks();
+
+        createAction();
+
+        AnchorTag tag = createTag();
+
+        // when
+        tag.doStartTag();
+
+        // then
+        Anchor component = (Anchor) tag.getComponent();
+        assertTrue(component.escapeHtmlBody());
+
+        tag.doEndTag();
+    }
+
 }
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java
index 778fb19..783d5ae 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java
@@ -40,8 +40,8 @@ public class CheckboxTest extends AbstractUITagTest {
      *         as key.
      */
     @Override
-    protected Map initializedGenericTagTestProperties() {
-        Map result = super.initializedGenericTagTestProperties();
+    protected Map<String, PropertyHolder> initializedGenericTagTestProperties() {
+        Map<String, PropertyHolder> result = super.initializedGenericTagTestProperties();
         new PropertyHolder("value", "true").addToMap(result);
         return result;
     }
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/FileTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/FileTest.java
index 32b9322..d5a296c 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/FileTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/FileTest.java
@@ -96,8 +96,8 @@ public class FileTest extends AbstractUITagTest {
      *         as key.
      */
     @Override
-    protected Map initializedGenericTagTestProperties() {
-        Map result = super.initializedGenericTagTestProperties();
+    protected Map<String, PropertyHolder> initializedGenericTagTestProperties() {
+        Map<String, PropertyHolder> result = super.initializedGenericTagTestProperties();
         new PropertyHolder("accept", "someAccepted").addToMap(result);
         new PropertyHolder("size", "101").addToMap(result);
         new PropertyHolder("value", "", "").addToMap(result);
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/SubmitTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/SubmitTest.java
index 6f573ae..99eff80 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/SubmitTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/SubmitTest.java
@@ -630,8 +630,8 @@ public class SubmitTest extends AbstractUITagTest {
      *         as key.
      */
     @Override
-    protected Map initializedGenericTagTestProperties() {
-        Map result = new HashMap();
+    protected Map<String, PropertyHolder> initializedGenericTagTestProperties() {
+        Map<String, PropertyHolder> result = new HashMap<>();
         new PropertyHolder("title", "someTitle").addToMap(result);
         new PropertyHolder("cssClass", "cssClass1", "class=\"cssClass1\"").addToMap(result);
         new PropertyHolder("cssStyle", "cssStyle1", "style=\"cssStyle1\"").addToMap(result);
@@ -652,8 +652,6 @@ public class SubmitTest extends AbstractUITagTest {
 
     /**
      * Test that by default submit tag body is HTML-escaped.
-     * 
-     * @throws Exception 
      */
     public void testSubmitWithBodyHTMLEscaped() throws Exception {
         TestAction testAction = (TestAction) action;
@@ -670,6 +668,7 @@ public class SubmitTest extends AbstractUITagTest {
         StrutsBodyContent body = new StrutsBodyContent(null);
         body.print("should HTML escape: < & >");
         tag.setBodyContent(body);
+        tag.setEscapeHtmlBody(true);
         tag.doStartTag();
         tag.doEndTag();
 
@@ -678,8 +677,6 @@ public class SubmitTest extends AbstractUITagTest {
 
     /**
      * Test that with htmlEscapeBody false submit tag body is not HTML-escaped.
-     * 
-     * @throws Exception 
      */
     public void testSubmitWithBodyNotHTMLEscaped() throws Exception {
         TestAction testAction = (TestAction) action;
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/TextareaTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/TextareaTest.java
index 54fa478..d94bbd2 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/TextareaTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/TextareaTest.java
@@ -130,8 +130,8 @@ public class TextareaTest extends AbstractUITagTest {
      *         as key.
      */
     @Override
-    protected Map initializedGenericTagTestProperties() {
-        Map result = super.initializedGenericTagTestProperties();
+    protected Map<String, PropertyHolder> initializedGenericTagTestProperties() {
+        Map<String, PropertyHolder> result = super.initializedGenericTagTestProperties();
         new PropertyHolder("cols", "10").addToMap(result);
         new PropertyHolder("rows", "11").addToMap(result);
         new PropertyHolder("readonly", "true", "readonly=\"readonly\"").addToMap(result);
diff --git a/core/src/test/resources/struts-escape-body.xml b/core/src/test/resources/struts-escape-body.xml
new file mode 100644
index 0000000..d3f7084
--- /dev/null
+++ b/core/src/test/resources/struts-escape-body.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+-->
+<!DOCTYPE struts PUBLIC
+          "-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
+          "http://struts.apache.org/dtds/struts-2.6.dtd">
+<struts>
+    <constant name="struts.ui.escapeHtmlBody" value="true"/>
+
+    <package name="default" extends="struts-default">
+    </package>
+
+</struts>