Merge branch 'master' of https://github.com/JCgH4164838Gh792C124B5/struts into localS2_26_OgnlUtilOptionalCache1

# Conflicts:
#	core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java
#	core/src/main/resources/struts-default.xml

Manually resolved conflicts.
This commit is contained in:
JCgH4164838Gh792C124B5
2022-03-06 21:51:33 -05:00
115 changed files with 1181 additions and 769 deletions
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-apps</artifactId>
<packaging>pom</packaging>
+2 -2
View File
@@ -24,12 +24,12 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-rest-showcase</artifactId>
<packaging>war</packaging>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
<name>Struts 2 Rest Showcase Webapp</name>
<description>Struts 2 Rest Showcase Example</description>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-showcase</artifactId>
@@ -27,22 +27,24 @@ import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.validation.SkipValidation;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.ScriptAssert;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.Date;
/**
* <!-- START SNIPPET: beanValidatationExample -->
*/
// <!-- START SNIPPET: beanValidationExample -->
@Namespace("/bean-validation")
@ParentPackage("bean-validation")
@Action(results = {
@Result(name = "input", location = "bean-validation.jsp"),
@Result(name = "success", location = "/WEB-INF/validation/successFieldValidatorsExample.jsp")
@Result(name = "input", location = "bean-validation.jsp"),
@Result(name = "success", location = "/WEB-INF/validation/successFieldValidatorsExample.jsp")
})
@FieldMatch(first = "fieldExpressionValidatorField", second = "requiredValidatorField", message = "requiredValidatorField and fieldExpressionValidatorField are not matching")
@ScriptAssert(lang = "javascript", script = "_this.dateValidatorField != null && _this.dateValidatorField.before(new java.util.Date())", message = "Date need to before now")
@@ -82,10 +84,10 @@ public class BeanValidationExampleAction extends ActionSupport {
private String fieldExpressionValidatorField = null;
@Action(value = "bean-validation", results = {
@Result(name = "success", location = "bean-validation.jsp")
@Result(name = "success", location = "bean-validation.jsp")
})
@SkipValidation
public String beanValidation(){
public String beanValidation() {
return SUCCESS;
}
@@ -150,7 +152,7 @@ public class BeanValidationExampleAction extends ActionSupport {
}
public void setFieldExpressionValidatorField(
String fieldExpressionValidatorField) {
String fieldExpressionValidatorField) {
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
}
@@ -163,8 +165,4 @@ public class BeanValidationExampleAction extends ActionSupport {
}
}
/**
* <!-- END SNIPPET: beanValidatationExample -->
*/
// <!-- END SNIPPET: beanValidationExample -->
@@ -113,7 +113,7 @@
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><s:a value="%{home}" escapeHtmlBody="false"><i class="glyphicon glyphicon-home"></i> Home</s:a></li>
<li><s:a value="%{home}"><i class="glyphicon glyphicon-home"></i> Home</s:a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="glyphicon glyphicon-cog"></i> Configuration
@@ -239,7 +239,7 @@
</li>
<li><s:a value="/person/index.html">Person Manager</s:a></li>
<li><s:a value="/skill/index.html">CRUD</s:a></li>
<li><s:a value="/wait/index.html" escapeHtmlBody="false">Execute &amp; Wait</s:a></li>
<li><s:a value="/wait/index.html">Execute &amp; Wait</s:a></li>
<li><s:a value="/token/index.html">Token</s:a></li>
<li><s:url var="url" namespace="/modelDriven" action="modelDriven"/><s:a
href="%{url}">Model Driven</s:a></li>
@@ -39,7 +39,7 @@
</div>
<s:url var="url" action="download"/>
<s:a href="%{url}" cssClass="btn btn-large btn-info" escapeHtmlBody="false"><i class="icon-picture"></i> Download image file.</s:a>
<s:a href="%{url}" cssClass="btn btn-large btn-info"><i class="icon-picture"></i> Download image file.</s:a>
</div>
<div class="col-md-6" style="text-align: center;">
<div class="alert alert-info">
@@ -47,7 +47,7 @@
</div>
<s:url var="url" action="download2"/>
<s:a href="%{url}" cssClass="btn btn-large btn-info" escapeHtmlBody="false"><i class="icon-download-alt"></i> Download ZIP file.</s:a>
<s:a href="%{url}" cssClass="btn btn-large btn-info"><i class="icon-download-alt"></i> Download ZIP file.</s:a>
</div>
</div>
</div>
@@ -125,7 +125,7 @@
<#else>
<img src="<@s.property value="%{#looseImageUrl}" />" width="381" height="44" />
</#if>
<@s.a href="%{#startHref}" escapeHtmlBody="false">
<@s.a href="%{#startHref}">
<img src="<@s.property value="%{#startImageUrl}" />" width="250" height="43" />
</@s.a>
<#else>
@@ -139,7 +139,7 @@
<@s.a href="%{#url}"
id="%{#currentCharacter}"
escapeHtmlBody="false"
>
<img height="36" alt="" src="<@s.property value="%{#chalkboardImageUrl}" />" width="36" border="0" />
</@s.a>
@@ -59,7 +59,7 @@
</div>
</div>
<div class="form-actions">
<@s.submit value="Create person" cssClass="btn btn-primary" escapeHtmlBody="false"/>
<@s.submit value="Create person" cssClass="btn btn-primary"/>
</div>
</@s.form>
</div>
@@ -35,7 +35,7 @@
<p>The text you've entered is ${text!''}<p/>
<@s.a href="javascript:history.back();" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back</@s.a>
<@s.a href="javascript:history.back();" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back</@s.a>
</div>
</div>
</div>
@@ -57,13 +57,13 @@
<@s.textfield label="Enter Some Text" name="text" />
<@s.submit action="actionPrefix" value="%{'action prefix'}" cssClass="btn" escapeHtmlBody="false" />
<@s.submit action="actionPrefix" value="%{'action prefix'}" cssClass="btn" />
<@s.submit method="alternateMethod" value="%{'method prefix'}" cssClass="btn" escapeHtmlBody="false" />
<@s.submit method="alternateMethod" value="%{'method prefix'}" cssClass="btn" />
<@s.submit value="Normal Submit" cssClass="btn" escapeHtmlBody="false" />
<@s.submit value="Normal Submit" cssClass="btn" />
<@s.submit action="redirectActionPrefixAction" value="%{'redirectAction without prefix'}" cssClass="btn" escapeHtmlBody="false" />
<@s.submit action="redirectActionPrefixAction" value="%{'redirectAction without prefix'}" cssClass="btn" />
</@s.form>
</div>
@@ -32,10 +32,10 @@
<div class="col-md-12">
<p>You have come to this page because you used an <strong>method</strong> prefix.<p/>
<p>The text you've enter is ${text!''}<p/>
<@s.a href="javascript:history.back();" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back</@s.a>
<@s.a href="javascript:history.back();" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back</@s.a>
</div>
</div>
</div>
@@ -32,10 +32,10 @@
<div class="col-md-12">
<p>You have come to this page because you did a normal submit.<p/>
<p>The text you've enter is %{text}<p/>
<@s.a href="javascript:history.back();" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back</@s.a>
<@s.a href="javascript:history.back();" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back</@s.a>
</div>
</div>
</div>
@@ -32,13 +32,13 @@
<div class="col-md-12">
<p>You have come to this page because you used an 'redirect-action' prefix.<p/>
<p>Because this is a <strong>redirect-action</strong>, the text will be lost, due to a redirection
implies a new request being issued from the client.<p/>
The text you've enter is ${text!''}<p/>
<@s.a href="javascript:history.back();" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back</@s.a>
<@s.a href="javascript:history.back();" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back</@s.a>
</div>
</div>
</div>
@@ -46,7 +46,7 @@
</s:iterator>
<s:url var="url" action="showAppendTagDemo" namespace="/tags/non-ui/appendIteratorTag" />
<s:a href="%{#url}" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
<s:a href="%{#url}" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
</div>
</div>
</div>
@@ -41,7 +41,7 @@
<s:url var="url" action="showGeneratorTagDemo" namespace="/tags/non-ui/iteratorGeneratorTag" />
<s:a href="%{#url}" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
<s:a href="%{#url}" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
</div>
</div>
</div>
@@ -45,7 +45,7 @@
</s:iterator>
<s:url var="url" action="showMergeTagDemo" namespace="/tags/non-ui/mergeIteratorTag" />
<s:a href="%{#url}" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
<s:a href="%{#url}" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
</div>
</div>
</div>
@@ -42,7 +42,7 @@
</s:subset>
<s:url var="url" action="showSubsetTagDemo" namespace="/tags/non-ui/subsetIteratorTag" />
<s:a href="%{#url}" cssClass="btn btn-info" escapeHtmlBody="false"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
<s:a href="%{#url}" cssClass="btn btn-info"><i class="icon icon-arrow-left"></i> Back To Input</s:a>
</div>
</div>
</div>
@@ -51,7 +51,7 @@
<@s.form action="transfer4">
<@s.token/>
<@s.textfield label="Amount" name="amount" required=true value="400"/>
<@s.submit value="Transfer money" cssClass="btn btn-primary" escapeHtmlBody="false"/>
<@s.submit value="Transfer money" cssClass="btn btn-primary"/>
</@s.form>
</div>
</div>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-assembly</artifactId>
+2 -2
View File
@@ -29,7 +29,7 @@
</parent>
<artifactId>struts2-bom</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Struts 2 Bill of Materials</name>
@@ -44,7 +44,7 @@
</licenses>
<properties>
<struts-version.version>2.6-SNAPSHOT</struts-version.version>
<struts-version.version>6.0.0-SNAPSHOT</struts-version.version>
<maven.site.skip>true</maven.site.skip>
<maven.site.deploy.skip>true</maven.site.deploy.skip>
</properties>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-osgi-admin-bundle</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-osgi-demo-bundle</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-osgi-bundles</artifactId>
+2 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-core</artifactId>
<packaging>jar</packaging>
@@ -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.
@@ -56,6 +56,9 @@ import com.opensymphony.xwork2.conversion.impl.DateConverter;
import com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor;
import com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor;
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
import org.apache.struts2.components.date.DateFormatter;
import org.apache.struts2.components.date.DateTimeFormatterAdapter;
import org.apache.struts2.components.date.SimpleDateFormatAdapter;
import org.apache.struts2.conversion.StrutsConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
@@ -227,6 +230,9 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
.factory(DateFormatter.class, "simpleDateFormatter", SimpleDateFormatAdapter.class, Scope.SINGLETON)
.factory(DateFormatter.class, "dateTimeFormatter", DateTimeFormatterAdapter.class, Scope.SINGLETON)
.factory(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSIONCACHE_FACTORY, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
.factory(OgnlCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFOCACHE_FACTORY, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
;
@@ -38,7 +38,8 @@ import java.lang.annotation.Target;
*
* <p>
* Application wide conversion:<br>
* The conversion rules will be assembled within the <code>xwork-conversion.properties</code> file within the classpath root.
* The conversion rules will be assembled within the <code>struts-conversion.properties</code> or
* <code>xwork-conversion.properties</code> (deprecated) file within the classpath root.
* Set type to: <code>type = ConversionType.APPLICATION</code>
* </p>
* <!-- END SNIPPET: description -->
@@ -1,187 +0,0 @@
/*
* 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.
*/
package com.opensymphony.xwork2.conversion.metadata;
import com.opensymphony.xwork2.conversion.annotations.ConversionRule;
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* <code>ConversionDescription</code>
*
* @author Rainer Hermanns
* @version $Id$
*
* @deprecated class will be removed
*/
@Deprecated
public class ConversionDescription {
/**
* Jakarta commons-logging reference.
*/
protected static Logger log = null;
public static final String KEY_PREFIX = "Key_";
public static final String ELEMENT_PREFIX = "Element_";
public static final String KEY_PROPERTY_PREFIX = "KeyProperty_";
public static final String DEPRECATED_ELEMENT_PREFIX = "Collection_";
/**
* Key used for type conversion of maps.
*/
String MAP_PREFIX = "Map_";
public String property;
public String typeConverter = "";
public String rule = "";
public String value = "";
public String fullQualifiedClassName;
public String type = null;
public ConversionDescription() {
log = LogManager.getLogger(this.getClass());
}
/**
* Creates an ConversionDescription with the specified property name.
*
* @param property property
*/
public ConversionDescription(String property) {
this.property = property;
log = LogManager.getLogger(this.getClass());
}
/**
* <p>
* Sets the property name to be inserted into the related conversion.properties file.<br>
* Note: Do not add COLLECTION_PREFIX or MAP_PREFIX keys to property names.
* </p>
*
* @param property The property to be converted.
*/
public void setProperty(String property) {
this.property = property;
}
/**
* Sets the class name of the type converter to be used.
*
* @param typeConverter The class name of the type converter.
*/
public void setTypeConverter(String typeConverter) {
this.typeConverter = typeConverter;
}
/**
* @param rule the rule prefix for COLLECTION_PREFIX or MAP_PREFIX key. Defaults to en empty String.
*/
public void setRule(String rule) {
if (rule != null && rule.length() > 0) {
if (rule.equals(ConversionRule.COLLECTION.toString())) {
this.rule = DefaultObjectTypeDeterminer.DEPRECATED_ELEMENT_PREFIX;
} else if (rule.equals(ConversionRule.ELEMENT.toString())) {
this.rule = DefaultObjectTypeDeterminer.ELEMENT_PREFIX;
} else if (rule.equals(ConversionRule.KEY.toString())) {
this.rule = DefaultObjectTypeDeterminer.KEY_PREFIX;
} else if (rule.equals(ConversionRule.KEY_PROPERTY.toString())) {
this.rule = DefaultObjectTypeDeterminer.KEY_PROPERTY_PREFIX;
} else if (rule.equals(ConversionRule.MAP.toString())) {
this.rule = MAP_PREFIX;
}
}
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* Returns the conversion description as property entry.
* <p>
* Example:<br>
* property.name = converter.className<br>
* Collection_property.name = converter.className<br>
* Map_property.name = converter.className
* KeyProperty_name = id
* </p>
*
* @return the conversion description as property entry.
*/
public String asProperty() {
StringWriter sw = new StringWriter();
PrintWriter writer = null;
try {
writer = new PrintWriter(sw);
writer.print(rule);
writer.print(property);
writer.print("=");
if ( rule.startsWith(DefaultObjectTypeDeterminer.KEY_PROPERTY_PREFIX) && value != null && value.length() > 0 ) {
writer.print(value);
} else {
writer.print(typeConverter);
}
} finally {
if (writer != null) {
writer.flush();
writer.close();
}
}
return sw.toString();
}
/**
* Returns the fullQualifiedClassName attribute is used to create the special <code>conversion.properties</code> file name.
*
* @return full qualified class name
*/
public String getFullQualifiedClassName() {
return fullQualifiedClassName;
}
/**
* The fullQualifiedClassName attribute is used to create the special <code>conversion.properties</code> file name.
*
* @param fullQualifiedClassName a full qualified class name
*/
public void setFullQualifiedClassName(String fullQualifiedClassName) {
this.fullQualifiedClassName = fullQualifiedClassName;
}
}
@@ -40,6 +40,7 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;
/**
* This interceptor sets all parameters on the value stack.
@@ -50,8 +51,11 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
protected static final int PARAM_NAME_MAX_LENGTH = 100;
private static final Pattern DMI_IGNORED_PATTERN = Pattern.compile("^(action|method):.*", Pattern.CASE_INSENSITIVE);
private int paramNameMaxLength = PARAM_NAME_MAX_LENGTH;
private boolean devMode = false;
private boolean dmiEnabled = false;
protected boolean ordered = false;
@@ -79,6 +83,11 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
this.acceptedPatterns = acceptedPatterns;
}
@Inject(value = StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, required = false)
protected void setDynamicMethodInvocation(String dmiEnabled) {
this.dmiEnabled = Boolean.parseBoolean(dmiEnabled);
}
/**
* If the param name exceeds the configured maximum length it will not be
* accepted.
@@ -101,13 +110,10 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
/**
* Compares based on number of '.' and '[' characters (fewer is higher)
*/
static final Comparator<String> rbCollator = new Comparator<String>() {
public int compare(String s1, String s2) {
int l1 = countOGNLCharacters(s1);
int l2 = countOGNLCharacters(s2);
return l1 < l2 ? -1 : (l2 < l1 ? 1 : s1.compareTo(s2));
}
static final Comparator<String> rbCollator = (s1, s2) -> {
int l1 = countOGNLCharacters(s1);
int l2 = countOGNLCharacters(s2);
return l1 < l2 ? -1 : (l2 < l1 ? 1 : s1.compareTo(s2));
};
@Override
@@ -286,6 +292,10 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
protected boolean acceptableName(String name) {
if (isIgnoredDMI(name)) {
LOG.trace("DMI is enabled, ignoring DMI method: {}", name);
return false;
}
boolean accepted = isWithinLengthLimit(name) && !isExcluded(name) && isAccepted(name);
if (devMode && accepted) { // notify only when in devMode
LOG.debug("Parameter [{}] was accepted and will be appended to action!", name);
@@ -293,6 +303,14 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
return accepted;
}
private boolean isIgnoredDMI(String name) {
if (dmiEnabled) {
return DMI_IGNORED_PATTERN.matcher(name).matches();
} else {
return false;
}
}
protected boolean isWithinLengthLimit(String name) {
boolean matchLength = name.length() <= paramNameMaxLength;
if (!matchLength) {
@@ -306,13 +306,13 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* A helper method for {@link ResourceBundle} bundle reload logic.
*
* Uses standard {@link ResourceBundle} methods to clear the bundle caches for the
*
* Uses standard {@link ResourceBundle} methods to clear the bundle caches for the
* {@link ClassLoader} instances that this class is aware of at the time of the call.
*
* The <code>clearCache()</code> methods have been available since Java 1.6, so
*
* The <code>clearCache()</code> methods have been available since Java 1.6, so
* it is anticipated the logic will work on any subsequent JVM versions.
*
*
* @since 2.6
*/
private void clearResourceBundleClassloaderCaches() {
@@ -326,14 +326,14 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* "Hacky" helper method that attempts to clear the Tomcat <code>ResourceEntry</code>
* {@link Map} using knowledge of the Tomcat source code.
*
* It relies on the {@link #TOMCAT_RESOURCE_ENTRIES_FIELD} field name, base class name
*
* It relies on the {@link #TOMCAT_RESOURCE_ENTRIES_FIELD} field name, base class name
* {@link #TOMCAT_WEBAPP_CLASSLOADER_BASE}. and descendant class names {@link #TOMCAT_WEBAPP_CLASSLOADER},
* {@link #TOMCAT_PARALLEL_WEBAPP_CLASSLOADER}, to keep the values identified in the constants.
* It appears to be valid for Tomcat versions 7-10 so far, but could become invalid at any time in the future
* when the resource handling logic in Tomcat changes.
*
* Note: With Java 9+, calling this method may result in "Illegal reflective access" warnings. Be aware
*
* Note: With Java 9+, calling this method may result in "Illegal reflective access" warnings. Be aware
* its logic may fail in a future version of Java that blocks the reflection calls needed for this method.
*/
private void clearTomcatCache() {
@@ -367,10 +367,10 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
/**
* Helper method that is intended to clear a {@link Map} instance by name.
*
*
* This method relies on reflection to perform its operations, and may be blocked in Java 9 and later,
* depending on the accessibility of the field.
*
*
* @param cl The {@link Class} of the obj parameter.
* @param obj The {@link Object} from which the named field is to be extracted (may be <code>null</code> for a static field).
* @param name The name of the field containing a {@link Map} reference.
@@ -433,9 +433,9 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
* Set the {@link #searchDefaultBundlesFirst} flag state. This flag may be used by descendant TextProvider
* implementations to determine if default bundles should be searched for messages first (before the standard
* flow of the {@link LocalizedTextProvider} implementation the descendant provides).
*
*
* @param searchDefaultBundlesFirst provide {@link String} "true" or "false" to set the flag state accordingly.
*
*
* @since 2.6
*/
@Inject(value = StrutsConstants.STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST, required = false)
@@ -490,7 +490,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
}
return bundle;
}
/**
* Clears all the internal lists.
*
@@ -566,17 +566,17 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
* against the default resource bundles. The default resource bundles are searched for a value using key first, then
* alternateKey when the first search fails, then utilizing defaultMessage (which may be <code>null</code>) if <em>both</em>
* key lookup operations fail.
*
*
* <p>
* A known use case is when a key indexes a collection (e.g. user.phone[0]) for which some specific keys may exist, but not all,
* along with a general key (e.g. user.phone[*]). In such cases the specific key would be passed in the key parameter and the
* general key would be passed in the alternateKey parameter.
* </p>
*
*
* @param key the initial key to search for a value within the default resource bundles.
* @param alternateKey the alternate (fall-back) key to search for a value within the default resource bundles, if the initial key lookup fails.
* @param locale the {@link Locale} to be used for the default resource bundle lookup.
* @param valueStack the {@link ValueStack} associated with the operation.
* @param valueStack the {@link ValueStack} associated with the operation.
* @param args the argument array for parameterized messages (may be <code>null</code>).
* @param defaultMessage the default message {@link String} to use if both key lookup operations fail.
* @return the {@link GetDefaultMessageReturnArg} result containing the processed message lookup (by key first, then alternateKey if key's lookup fails).
@@ -616,11 +616,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
MessageFormat mf = buildMessageFormat(message, locale);
return formatWithNullDetection(mf, args);
} catch (MissingResourceException e) {
if (devMode) {
LOG.warn("Missing key [{}] in bundle [{}]!", key, bundleName);
} else {
LOG.debug("Missing key [{}] in bundle [{}]!", key, bundleName);
}
LOG.debug("Missing key [{}] in bundle [{}]!", key, bundleName);
return null;
}
}
@@ -18,6 +18,7 @@
*/
package org.apache.struts2;
import org.apache.struts2.components.date.DateFormatter;
import org.apache.struts2.dispatcher.mapper.CompositeActionMapper;
/**
@@ -132,6 +133,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";
@@ -442,4 +446,7 @@ 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";
/** See {@link org.apache.struts2.components.Date#setDateFormatter(DateFormatter)} */
public static final String STRUTS_DATE_FORMATTER = "struts.date.formatter";
}
@@ -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();
@@ -124,6 +112,8 @@ public class Anchor extends ClosingUIBean {
addParameter("href", ensureAttributeSafelyNotEscaped(builtHref));
}
}
addParameter("escapeHtmlBody", escapeHtmlBody);
}
@Inject(StrutsConstants.STRUTS_URL_INCLUDEPARAMS)
@@ -276,7 +266,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 = "false")
public void setEscapeHtmlBody(boolean escapeHtmlBody) {
this.escapeHtmlBody = escapeHtmlBody;
}
@@ -75,7 +75,8 @@ public class Checkbox extends UIBean {
}
if (submitUnchecked != null) {
addParameter("submitUnchecked", findValue(submitUnchecked, Boolean.class));
Object parsedValue = findValue(submitUnchecked, Boolean.class);
addParameter("submitUnchecked", parsedValue == null ? Boolean.valueOf(submitUnchecked) : parsedValue);
} else {
addParameter("submitUnchecked", false);
}
@@ -48,7 +48,7 @@ import com.opensymphony.xwork2.util.ValueStack;
allowDynamicAttributes = true)
public class CheckboxList extends ListUIBean {
final public static String TEMPLATE = "checkboxlist";
public CheckboxList(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
super(stack, request, response);
}
@@ -56,9 +56,19 @@ public class CheckboxList extends ListUIBean {
protected String getDefaultTemplate() {
return TEMPLATE;
}
public void evaluateExtraParams() {
super.evaluateExtraParams();
}
}
/**
* Checkboxlist tag requires lazy evaluation as list of tags is dynamically generated using <s:iterator/>
*
* @return boolean true by default
*/
@Override
protected boolean lazyEvaluation() {
return true;
}
}
@@ -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;
}
@@ -378,9 +384,8 @@ public class Component {
return expression;
}
} else {
expression = stripExpression(expression);
return getStack().findValue(expression, toType, throwExceptionOnELFailure);
String strippedExpression = stripExpression(expression);
return getStack().findValue(strippedExpression, toType, throwExceptionOnELFailure);
}
}
@@ -536,7 +541,7 @@ public class Component {
* @since 2.6
*/
public boolean escapeHtmlBody() {
return true;
return escapeHtmlBody;
}
/**
@@ -572,16 +577,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;
}
@@ -18,29 +18,29 @@
*/
package org.apache.struts2.components;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.components.date.DateFormatter;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import java.io.IOException;
import java.io.Writer;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* <!-- START SNIPPET: javadoc -->
*
* <p>
* Format Date object in different ways.
* <p>
* The date tag will allow you to format a Date in a quick and easy way.
@@ -59,6 +59,12 @@ import java.util.List;
* </p>
*
* <p>
* <b>Note</b>: Since Struts 2.6 a new Java 8 API has been used to format the Date, it's based on
* <a href="https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html">DateTimeFormatter</a>
* which uses a bit different patterns.
* </p>
*
* <p>
* Configurable attributes are:
* </p>
*
@@ -130,8 +136,8 @@ import java.util.List;
* <td>if one is not found DateFormat.MEDIUM format will be used</td>
* </tr>
* </table>
*
*
* <p>
* <p>
* <!-- END SNIPPET: javadoc -->
*
* <p><b>Examples</b></p>
@@ -145,12 +151,12 @@ import java.util.List;
* </pre>
*
* <code>Date</code>
*
*/
@StrutsTag(name="date", tldBodyContent="empty", tldTagClass="org.apache.struts2.views.jsp.DateTag", description="Render a formatted date.")
@StrutsTag(name = "date", tldBodyContent = "empty", tldTagClass = "org.apache.struts2.views.jsp.DateTag", description = "Render a formatted date.")
public class Date extends ContextBean {
private static final Logger LOG = LogManager.getLogger(Date.class);
/**
* Property name to fall back when no format is specified
*/
@@ -202,17 +208,18 @@ public class Date extends ContextBean {
private String timezone;
private DateFormatter dateFormatter;
public Date(ValueStack stack) {
super(stack);
}
private TextProvider findProviderInStack() {
for (Object o : getStack().getRoot()) {
if (o instanceof TextProvider) {
return (TextProvider) o;
}
}
return null;
/**
* An instance of {@link DateFormatter}
*/
@Inject
public void setDateFormatter(DateFormatter dateFormatter) {
this.dateFormatter = dateFormatter;
}
/**
@@ -280,6 +287,8 @@ public class Date extends ContextBean {
@Override
public boolean end(Writer writer, String body) {
TextProvider textProvider = findProviderInStack();
ZonedDateTime date = null;
final ZoneId tz = getTimeZone();
// find the name on the valueStack
@@ -292,26 +301,27 @@ public class Date extends ContextBean {
date = Instant.ofEpochMilli((long) dateObject).atZone(tz);
} else if (dateObject instanceof LocalDateTime) {
date = ((LocalDateTime) dateObject).atZone(tz);
} else if (dateObject instanceof LocalDate) {
date = ((LocalDate) dateObject).atStartOfDay(tz);
} else if (dateObject instanceof Instant) {
date = ((Instant) dateObject).atZone(tz);
} else {
if (devMode) {
TextProvider tp = findProviderInStack();
String developerNotification = "";
if (tp != null) {
developerNotification = findProviderInStack().getText(
"devmode.notification",
"Developer Notification:\n{0}",
new String[]{
"Expression [" + name + "] passed to <s:date/> tag which was evaluated to [" + dateObject + "]("
+ (dateObject != null ? dateObject.getClass() : "null") + ") isn't supported!"
}
if (textProvider != null) {
developerNotification = textProvider.getText(
"devmode.notification",
"Developer Notification:\n{0}",
new String[]{
"Expression [" + name + "] passed to <s:date/> tag which was evaluated to [" + dateObject + "]("
+ (dateObject != null ? dateObject.getClass() : "null") + ") isn't supported!"
}
);
}
LOG.warn(developerNotification);
} else {
LOG.debug("Expression [{}] passed to <s:date/> tag which was evaluated to [{}]({}) isn't supported!",
name, dateObject, (dateObject != null ? dateObject.getClass() : "null"));
name, dateObject, (dateObject != null ? dateObject.getClass() : "null"));
}
}
@@ -321,33 +331,11 @@ public class Date extends ContextBean {
}
String msg;
if (date != null) {
TextProvider tp = findProviderInStack();
if (tp != null) {
if (textProvider != null) {
if (nice) {
msg = formatTime(tp, date);
msg = formatTime(textProvider, date);
} else {
DateTimeFormatter dtf;
if (format == null) {
String globalFormat = null;
// if the format is not specified, fall back using the
// defined property DATETAG_PROPERTY
globalFormat = tp.getText(DATETAG_PROPERTY);
// if tp.getText can not find the property then the
// returned string is the same as input =
// DATETAG_PROPERTY
if (globalFormat != null
&& !DATETAG_PROPERTY.equals(globalFormat)) {
dtf = DateTimeFormatter.ofPattern(globalFormat, ActionContext.getContext().getLocale());
} else {
dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(ActionContext.getContext().getLocale());
}
} else {
dtf = DateTimeFormatter.ofPattern(format, ActionContext.getContext().getLocale());
}
msg = dtf.format(date);
msg = formatDate(textProvider, date);
}
if (msg != null) {
try {
@@ -365,6 +353,20 @@ public class Date extends ContextBean {
return super.end(writer, "");
}
private String formatDate(TextProvider textProvider, ZonedDateTime date) {
String useFormat = format;
if (useFormat == null) {
// if the format is not specified, fall back using the defined property DATETAG_PROPERTY
useFormat = textProvider.getText(DATETAG_PROPERTY);
if (DATETAG_PROPERTY.equals(useFormat)) {
// if tp.getText can not find the property then the
// returned string is the same as input = DATETAG_PROPERTY
useFormat = null;
}
}
return dateFormatter.format(date, useFormat);
}
private ZoneId getTimeZone() {
ZoneId tz = ZoneId.systemDefault();
if (timezone != null) {
@@ -378,17 +380,26 @@ public class Date extends ContextBean {
return tz;
}
@StrutsTagAttribute(description="Date or DateTime format pattern", rtexprvalue=false)
private TextProvider findProviderInStack() {
for (Object o : getStack().getRoot()) {
if (o instanceof TextProvider) {
return (TextProvider) o;
}
}
return null;
}
@StrutsTagAttribute(description = "Date or DateTime format pattern")
public void setFormat(String format) {
this.format = format;
}
@StrutsTagAttribute(description="Whether to print out the date nicely", type="Boolean", defaultValue="false")
@StrutsTagAttribute(description = "Whether to print out the date nicely", type = "Boolean", defaultValue = "false")
public void setNice(boolean nice) {
this.nice = nice;
}
@StrutsTagAttribute(description = "The specific timezone in which to format the date", required = false)
@StrutsTagAttribute(description = "The specific timezone in which to format the date")
public void setTimezone(String timezone) {
this.timezone = timezone;
}
@@ -400,7 +411,7 @@ public class Date extends ContextBean {
return name;
}
@StrutsTagAttribute(description="The date value to format", required=true)
@StrutsTagAttribute(description = "The date value to format", required = true)
public void setName(String name) {
this.name = name;
}
@@ -195,7 +195,6 @@ public abstract class ListUIBean extends UIBean {
this.listTitle = listTitle;
}
public void setThrowExceptionOnNullValueAttribute(boolean throwExceptionOnNullValueAttribute) {
this.throwExceptionOnNullValueAttribute = throwExceptionOnNullValueAttribute;
}
@@ -57,7 +57,7 @@ import javax.servlet.http.HttpServletResponse;
allowDynamicAttributes = true)
public class Radio extends ListUIBean {
final public static String TEMPLATE = "radiomap";
public Radio(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
super(stack, request, response);
}
@@ -65,8 +65,19 @@ public class Radio extends ListUIBean {
protected String getDefaultTemplate() {
return TEMPLATE;
}
public void evaluateExtraParams() {
super.evaluateExtraParams();
}
}
/**
* Radio tag requires lazy evaluation as list of tags is dynamically generated using <s:iterator/>
*
* @return boolean true by default
*/
@Override
protected boolean lazyEvaluation() {
return true;
}
}
@@ -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);
@@ -73,7 +75,7 @@ public class Submit extends FormButton {
value = "Submit";
}
if (((key != null)) && (value == null)) {
if ((key != null) && (value == null)) {
this.value = "%{getText('"+key +"')}";
}
@@ -83,8 +85,11 @@ public class Submit extends FormButton {
public void evaluateExtraParams() {
super.evaluateExtraParams();
if (src != null)
if (src != null) {
addParameter("src", findString(src));
}
addParameter("escapeHtmlBody", escapeHtmlBody);
}
/**
@@ -101,7 +106,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 = "false")
public void setEscapeHtmlBody(boolean escapeHtmlBody) {
this.escapeHtmlBody = escapeHtmlBody;
}
@@ -111,18 +116,6 @@ public class Submit extends FormButton {
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;
}
/**
* Overrides to be able to render body in a template rather than always before the template
*/
@@ -20,7 +20,9 @@ package org.apache.struts2.components;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -31,6 +33,7 @@ import org.apache.struts2.components.template.TemplateEngine;
import org.apache.struts2.components.template.TemplateEngineManager;
import org.apache.struts2.components.template.TemplateRenderingContext;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.apache.struts2.util.ComponentUtils;
import org.apache.struts2.util.TextProviderHelper;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.views.util.ContextUtil;
@@ -699,11 +702,13 @@ public abstract class UIBean extends Component {
}
if (requiredLabel != null) {
addParameter("required", findValue(requiredLabel, Boolean.class));
Object parsedValue = findValue(requiredLabel, Boolean.class);
addParameter("required", parsedValue == null ? Boolean.valueOf(requiredLabel) : parsedValue);
}
if (disabled != null) {
addParameter("disabled", findValue(disabled, Boolean.class));
Object parsedValue = findValue(disabled, Boolean.class);
addParameter("disabled", parsedValue == null ? Boolean.valueOf(disabled) : parsedValue);
}
if (tabindex != null) {
@@ -883,9 +888,9 @@ public abstract class UIBean extends Component {
this.addParameter("tooltipDelay", findString(this.tooltipDelay));
if (this.javascriptTooltip != null) {
Boolean jsTooltips = (Boolean) findValue(this.javascriptTooltip, Boolean.class);
Object jsTooltips = findValue(this.javascriptTooltip, Boolean.class);
//TODO use a Boolean model when tooltipConfig is dropped
this.addParameter("jsTooltipEnabled", jsTooltips.toString());
this.addParameter("jsTooltipEnabled", jsTooltips == null ? this.javascriptTooltip : jsTooltips.toString());
if (form != null)
form.addParameter("hasTooltip", jsTooltips);
@@ -965,7 +970,7 @@ public abstract class UIBean extends Component {
// 1] UI component's tooltipConfig attribute OR
// 2] <param name="tooltip" value="" /> param tag value attribute
result = new LinkedHashMap<>((Map) tooltipConfigObj);
result = new LinkedHashMap<String, String>((Map) tooltipConfigObj);
} else if (tooltipConfigObj instanceof String) {
// we get this if its configured using
@@ -1272,10 +1277,16 @@ public abstract class UIBean extends Component {
public void setDynamicAttributes(Map<String, String> tagDynamicAttributes) {
for (Map.Entry<String, String> entry : tagDynamicAttributes.entrySet()) {
String entryKey = entry.getKey();
String attrName = entry.getKey();
String attrValue = entry.getValue();
if (!isValidTagAttribute(entryKey)) {
dynamicAttributes.put(entryKey, entry.getValue());
if (!isValidTagAttribute(attrName)) {
if (ComponentUtils.containsExpression(attrValue) && !lazyEvaluation()) {
String translated = TextParseUtil.translateVariables('%', attrValue, stack);
dynamicAttributes.put(attrName, ObjectUtils.defaultIfNull(translated, attrValue));
} else {
dynamicAttributes.put(attrName, attrValue);
}
}
}
}
@@ -1296,4 +1307,14 @@ public abstract class UIBean extends Component {
}
}
/**
* Used to avoid evaluating attributes in {@link #evaluateParams()} or {@link #evaluateExtraParams()}
* as evaluation will happen in tag's template
*
* @return boolean false if evaluation should be performed in ftl
*/
protected boolean lazyEvaluation() {
return false;
}
}
@@ -0,0 +1,40 @@
/*
* 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.
*/
package org.apache.struts2.components.date;
import java.time.temporal.TemporalAccessor;
/**
* Allows defines a wrapper around different formatting APIs, like old SimpleDateFormat
* and new DateTimeFormatter introduced in Java 8 Date/Time API
* <p>
* New instance will be injected using {@link org.apache.struts2.StrutsConstants#STRUTS_DATE_FORMATTER}
*/
public interface DateFormatter {
/**
* Formats provided temporal with the given format
*
* @param temporal Java 8 {@link TemporalAccessor}
* @param format implementation specific format
* @return a string representation of the formatted `temporal`
*/
String format(TemporalAccessor temporal, String format);
}
@@ -0,0 +1,43 @@
/*
* 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.
*/
package org.apache.struts2.components.date;
import com.opensymphony.xwork2.ActionContext;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
import java.util.Locale;
public class DateTimeFormatterAdapter implements DateFormatter {
@Override
public String format(TemporalAccessor temporal, String format) {
DateTimeFormatter dtf;
Locale locale = ActionContext.getContext().getLocale();
if (format == null) {
dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(locale);
} else {
dtf = DateTimeFormatter.ofPattern(format, locale);
}
return dtf.format(temporal);
}
}
@@ -0,0 +1,44 @@
/*
* 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.
*/
package org.apache.struts2.components.date;
import com.opensymphony.xwork2.ActionContext;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Locale;
public class SimpleDateFormatAdapter implements DateFormatter {
@Override
public String format(TemporalAccessor temporal, String format) {
DateFormat df;
Locale locale = ActionContext.getContext().getLocale();
if (format == null) {
df = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM, locale);
} else {
df = new SimpleDateFormat(format, locale);
}
return df.format(new Date(Instant.from(temporal).toEpochMilli()));
}
}
@@ -148,16 +148,13 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
}
};
LOG.debug("Puts action on the top of ValueStack, just before the tag");
action = stack.pop();
LOG.debug("Push tag on top of the stack");
stack.push(templateContext.getTag());
stack.push(action);
try {
template.process(model, writer);
} finally {
stack.pop(); // removes action
stack.pop(); // removes tag
stack.push(action); // puts back action
LOG.debug("Removes tag from top of the stack");
stack.pop();
}
}
@@ -54,13 +54,12 @@ import com.opensymphony.xwork2.util.PatternMatcher;
import com.opensymphony.xwork2.util.TextParser;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import com.opensymphony.xwork2.util.reflection.ReflectionContextFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import com.opensymphony.xwork2.validator.ActionValidatorManager;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.components.UrlRenderer;
import org.apache.struts2.components.date.DateFormatter;
import org.apache.struts2.dispatcher.DispatcherErrorHandler;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
@@ -422,6 +421,8 @@ public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider {
alias(NotExcludedAcceptedPatternsChecker.class, StrutsConstants.STRUTS_NOT_EXCLUDED_ACCEPTED_PATTERNS_CHECKER
, builder, props, Scope.SINGLETON);
alias(DateFormatter.class, StrutsConstants.STRUTS_DATE_FORMATTER, builder, props, Scope.SINGLETON);
switchDevMode(props);
}
@@ -45,25 +45,23 @@ import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
* </p>
*
* <ul>
*
* <li>{@link ServletContextAware}</li>
*
* <li>{@link org.apache.struts2.action.ServletContextAware}</li>
* <li>{@link ServletRequestAware}</li>
*
* <li>{@link org.apache.struts2.action.ServletRequestAware}</li>
* <li>{@link ServletResponseAware}</li>
*
* <li>{@link org.apache.struts2.action.ServletResponseAware}</li>
* <li>{@link ParameterAware} - deprecated since 2.5.4, please use {@link HttpParametersAware}</li>
*
* <li>{@link HttpParametersAware}</li>
*
* <li>{@link org.apache.struts2.action.ParametersAware}</li>
* <li>{@link RequestAware}</li>
*
* <li>{@link org.apache.struts2.action.ServletRequestAware}</li>
* <li>{@link SessionAware}</li>
*
* <li>{@link org.apache.struts2.action.SessionAware}</li>
* <li>{@link ApplicationAware}</li>
*
* <li>{@link org.apache.struts2.action.ApplicationAware}</li>
* <li>{@link PrincipalAware}</li>
*
* <li>{@link org.apache.struts2.action.PrincipalAware}</li>
* </ul>
*
* <!-- END SNIPPET: description -->
@@ -101,13 +99,19 @@ import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
* </pre>
*
* @see ServletContextAware
* @see org.apache.struts2.action.ServletContextAware
* @see ServletRequestAware
* @see org.apache.struts2.action.ServletRequestAware
* @see ServletResponseAware
* @see org.apache.struts2.action.ServletResponseAware
* @see ParameterAware
* @see ParametersAware
* @see org.apache.struts2.action.ParametersAware
* @see SessionAware
* @see org.apache.struts2.action.SessionAware
* @see ApplicationAware
* @see org.apache.struts2.action.ApplicationAware
* @see PrincipalAware
* @see org.apache.struts2.action.PrincipalAware
*/
public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {
@@ -159,7 +163,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
if (action instanceof ApplicationAware) {
((ApplicationAware) action).setApplication(context.getApplication());
}
if (action instanceof org.apache.struts2.action.ApplicationAware) {
((org.apache.struts2.action.ApplicationAware) action).withApplication(context.getApplication());
}
@@ -167,7 +171,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
if (action instanceof SessionAware) {
((SessionAware) action).setSession(context.getSession());
}
if (action instanceof org.apache.struts2.action.SessionAware) {
((org.apache.struts2.action.SessionAware) action).withSession(context.getSession());
}
@@ -179,7 +183,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
if (action instanceof PrincipalAware) {
HttpServletRequest request = context.getServletRequest();
if(request != null) {
// We are in servtlet environment, so principal information resides in HttpServletRequest
// We are in servlet environment, so principal information resides in HttpServletRequest
((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request));
}
}
@@ -71,11 +71,6 @@ public class TextProviderHelper {
} else {
LOG.warn("Could not locate the message resource '{}' as there is no TextProvider in the ValueStack.", key);
}
if (defaultMessage.equals(msg)) {
LOG.warn("The default value expression '{}' was evaluated and did not match a property. The literal value '{}' will be used.", defaultMessage, defaultMessage);
} else {
LOG.warn("The default value expression '{}' evaluated to '{}'", defaultMessage, msg);
}
}
}
return msg;
@@ -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;
}
@@ -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) {
@@ -151,6 +151,11 @@ struts.ui.theme.expansion.token=~~~
### Sets the default template type. Either ftl, vm, or jsp
struts.ui.templateSuffix=ftl
### Sets a global flag which will escape html body of Anchor, Submit and Component tag
### You can control this flag per tag, e.g.: <s:a ... escapeHtmlTag="true">...</s:a>
### and this take precedence over the global flag
# struts.ui.escapeHtmlBody=true
### Configuration reloading
### This will cause the configuration to reload struts.xml when it is changed
# struts.configuration.xml.reload=false
@@ -256,7 +261,7 @@ struts.handle.exception=true
### Applies maximum length allowed on OGNL expressions for security enhancement (optional)
###
### **WARNING**: If developers enable this option (by configuration) they should make sure that they understand the implications of setting
### **WARNING**: If developers enable this option (by configuration) they should make sure that they understand the implications of setting
### struts.ognl.expressionMaxLength. They must choose a value large enough to permit ALL valid OGNL expressions used within the application.
### Values larger than the 200-400 range have diminishing security value (at which point it is really only a "style guard" for long OGNL
### expressions in an application. Setting a value of null or "" will also disable the feature.
@@ -264,4 +269,10 @@ struts.handle.exception=true
### NOTE: The sample line below is *INTENTIONALLY* commented out, as this feature is disabled by default.
# struts.ognl.expressionMaxLength=256
### Defines which named instance of DateFormatter to use, there are two instances:
### - simpleDateFormatter (based on SimpleDateFormat)
### - dateTimeFormatter (based on Java 8 Date/Time API)
### These formatters are using a slightly different patterns, please check JavaDocs of both and more details is in WW-5016
struts.date.formatter=dateTimeFormatter
### END SNIPPET: complete_file
+4 -1
View File
@@ -216,7 +216,7 @@
<bean type="com.opensymphony.xwork2.UnknownHandlerManager" class="com.opensymphony.xwork2.DefaultUnknownHandlerManager" name="struts" />
<bean type="org.apache.struts2.dispatcher.DispatcherErrorHandler" name="struts" class="org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler" />
<!-- Silly workarounds for OGNL since there is currently no way to flush its internal caches -->
<bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
<bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
@@ -228,6 +228,9 @@
<bean type="com.opensymphony.xwork2.config.providers.ValueSubstitutor" class="com.opensymphony.xwork2.config.providers.EnvsValueSubstitutor" scope="singleton"/>
<bean type="org.apache.struts2.components.date.DateFormatter" name="simpleDateFormatter" class="org.apache.struts2.components.date.SimpleDateFormatAdapter" scope="singleton"/>
<bean type="org.apache.struts2.components.date.DateFormatter" name="dateTimeFormatter" class="org.apache.struts2.components.date.DateTimeFormatterAdapter" scope="singleton"/>
<bean type="com.opensymphony.xwork2.ognl.OgnlCacheFactory" name="struts.ognl.expressionCacheFactory" class="com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory" scope="singleton"/>
<bean type="com.opensymphony.xwork2.ognl.OgnlCacheFactory" name="struts.ognl.beanInfoCacheFactory" class="com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory" scope="singleton"/>
@@ -30,7 +30,7 @@
<#assign itemKeyStr = stack.findString('top')>
</#if>
<#if parameters.listLabelKey??>
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale
file for it's localized value. This is then used as a label -->
<#assign itemValue = struts.getText(stack.findString(parameters.listLabelKey))/>
<#elseif parameters.listValue??>
@@ -95,9 +95,10 @@
<#include "/${parameters.templateDir}/${parameters.expandTheme}/css.ftl" />
<#include "/${parameters.templateDir}/${parameters.expandTheme}/scripting-events.ftl" />
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
<#global evaluate_dynamic_attributes = true/>
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
/>
<label<#rt/>
<label<#rt/>
<#if parameters.id?has_content>
for="${parameters.id}-${itemCount}"<#rt/>
<#else>
@@ -106,11 +107,10 @@
class="checkboxLabel">${itemValue}</label>
</@s.iterator>
<#else>
&nbsp;
</#if>
<input type="hidden" id="__multiselect_${parameters.id}" name="__multiselect_${parameters.name}"
value=""<#rt/>
<#if parameters.disabled!false>
disabled="disabled"<#rt/>
</#if>
/>
/>
@@ -30,7 +30,11 @@
<#list aKeys?filter(acceptKey) as aKey><#rt/>
<#assign keyValue = parameters.dynamicAttributes.get(aKey)/>
<#if keyValue?is_string>
<#assign value = struts.translateVariables(keyValue)!keyValue/>
<#if evaluate_dynamic_attributes!false == true>
<#assign value = struts.translateVariables(keyValue)!keyValue/><#rt/>
<#else>
<#assign value = keyValue/><#rt/>
</#if>
<#else>
<#assign value = keyValue?string/>
</#if>
@@ -27,7 +27,7 @@
<#assign itemKeyStr = stack.findString('top')>
</#if>
<#if parameters.listValueKey??>
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale
file for it's localized value. This is then used as a label -->
<#assign valueKey = stack.findString(parameters.listValueKey)!''/>
<#if valueKey?has_content>
@@ -94,9 +94,10 @@
<#include "/${parameters.templateDir}/${parameters.expandTheme}/css.ftl" />
<#include "/${parameters.templateDir}/${parameters.expandTheme}/scripting-events.ftl" />
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
<#global evaluate_dynamic_attributes = true/>
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
/><#rt/>
<label for="${parameters.id}${itemKeyStr?replace(".", "_")}"<#include "/${parameters.templateDir}/${parameters.expandTheme}/css.ftl"/>><#rt/>
${itemValue}<#t/>
</label>
</@s.iterator>
</@s.iterator>
@@ -112,7 +112,7 @@
<tr>
<td align="left" valign="top">escapeHtmlBody</td>
<td align="left" valign="top">false</td>
<td align="left" valign="top">true</td>
<td align="left" valign="top">false</td>
<td align="left" valign="top">false</td>
<td align="left" valign="top">Boolean</td>
<td align="left" valign="top">Specifies whether to HTML-escape the tag body or not</td>
@@ -88,7 +88,7 @@
<tr>
<td align="left" valign="top">escapeHtmlBody</td>
<td align="left" valign="top">false</td>
<td align="left" valign="top">true</td>
<td align="left" valign="top">false</td>
<td align="left" valign="top">false</td>
<td align="left" valign="top">Boolean</td>
<td align="left" valign="top">Specifies whether to HTML-escape the tag body or not</td>
@@ -730,6 +730,33 @@ public class ParametersInterceptorTest extends XWorkTestCase {
assertEquals(expected, actual);
}
public void testDMIMethodsAreIgnored() throws Exception {
// given
ParametersInterceptor interceptor = createParametersInterceptor();
final Map<String, Object> actual = injectValueStackFactory(interceptor);
ValueStack stack = injectValueStack(actual);
final Map<String, Object> expected = new HashMap<String, Object>() {
{
put("ordinary.bean", "value");
}
};
Map<String, Object> parameters = new HashMap<String, Object>() {
{
put("ordinary.bean", "value");
put("action:", "myAction");
put("method:", "doExecute");
}
};
// when
interceptor.setParameters(new NoParametersAction(), stack, HttpParameters.create(parameters).build());
// then
assertEquals(expected, actual);
}
public void testBeanListSingleValue() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put("beanList.name", new String[]{"Superman"});
@@ -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();
}
}
@@ -0,0 +1,90 @@
/*
* 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.
*/
package org.apache.struts2.components;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.components.date.SimpleDateFormatAdapter;
import java.io.StringWriter;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Map;
public class DateTest extends StrutsInternalTestCase {
private Map<String, Object> context;
private ValueStack stack;
public void testSupportSimpleDateTimeFormat() {
// given
Date date = new Date(stack);
date.setDateFormatter(new SimpleDateFormatAdapter());
String format = "EEEE MMMM dd, hh:mm aa";
java.util.Date now = new java.util.Date();
String expected = new SimpleDateFormat(format, ActionContext.getContext().getLocale()).format(now);
context.put("myDate", now);
Writer writer = new StringWriter();
// when
date.setFormat(format);
date.setName("myDate");
date.setNice(false);
date.start(writer);
date.end(writer, "");
// then
assertEquals(expected, writer.toString());
}
public void testDefaultFormat() {
// given
Date date = new Date(stack);
date.setDateFormatter(new SimpleDateFormatAdapter());
java.util.Date now = new java.util.Date();
String expected = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM, ActionContext.getContext().getLocale()).format(now);
context.put("myDate", now);
Writer writer = new StringWriter();
// when
date.setName("myDate");
date.setNice(false);
date.start(writer);
date.end(writer, "");
// then
assertEquals(expected, writer.toString());
}
@Override
public void setUp() throws Exception {
super.setUp();
stack = container.getInstance(ValueStackFactory.class).createValueStack();
context = stack.getContext();
}
}
@@ -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,50 @@ 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();
}
public void testTagAttributeTakesPrecedenceOverInjectEscapeHtmlBodyFlag() 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();
tag.setEscapeHtmlBody("false");
// when
tag.doStartTag();
// then
Anchor component = (Anchor) tag.getComponent();
assertFalse(component.escapeHtmlBody());
tag.doEndTag();
}
}
@@ -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;
}
@@ -19,35 +19,33 @@
package org.apache.struts2.views.jsp.ui;
import com.opensymphony.xwork2.ActionContext;
import org.apache.struts2.TestAction;
import org.apache.struts2.components.Component;
import org.apache.struts2.components.DateTextField;
import org.apache.struts2.views.jsp.AbstractTagTest;
import org.apache.struts2.views.jsp.DateTag;
import javax.servlet.jsp.JspException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.apache.struts2.components.Component;
import org.apache.struts2.components.DateTextField;
/**
* Unit test for {@link org.apache.struts2.components.Date}.
*
*/
public class DateTagTest extends AbstractTagTest {
private DateTag tag;
public void testCustomFormat() throws Exception {
public void testCustomFormatForDateTime() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setName("myDate");
@@ -62,13 +60,55 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatForLong() throws Exception {
String format = "yyyy/MM/dd";
long now = new Date().getTime();
String formatted = DateTimeFormatter.ofPattern(format).format(Instant.ofEpochMilli(now).atZone(ZoneId.systemDefault()));
context.put("myDate", now);
tag.setName("myDate");
tag.setNice(false);
tag.setFormat(format);
tag.doStartTag();
tag.doEndTag();
assertEquals(formatted, writer.toString());
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
DateTag freshTag = new DateTag();
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatForDate() throws Exception {
String format = "yyyy/MM/dd";
LocalDate now = LocalDate.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setName("myDate");
tag.setNice(false);
tag.setFormat(format);
tag.doStartTag();
tag.doEndTag();
assertEquals(formatted, writer.toString());
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
DateTag freshTag = new DateTag();
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormat_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
@@ -86,13 +126,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomGlobalFormatFormat() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
((TestAction) action).setText(org.apache.struts2.components.Date.DATETAG_PROPERTY, format);
@@ -106,10 +146,8 @@ public class DateTagTest extends AbstractTagTest {
public void testCustomFormatWithTimezone() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = Calendar.getInstance(TimeZone.getTimeZone("GMT+1")).getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(TimeZone.getTimeZone("GMT+1"));
String formatted = sdf.format(now);
LocalDateTime now = LocalDateTime.now(ZoneId.of("GMT+1"));
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setName("myDate");
@@ -126,15 +164,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatWithTimezone_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = Calendar.getInstance(TimeZone.getTimeZone("GMT+1")).getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(TimeZone.getTimeZone("GMT+1"));
String formatted = sdf.format(now);
LocalDateTime now = LocalDateTime.now(ZoneId.of("GMT+1"));
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
@@ -153,15 +189,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatWithTimezoneAsExpression() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = Calendar.getInstance(TimeZone.getTimeZone("GMT+2")).getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(TimeZone.getTimeZone("GMT+2"));
String formatted = sdf.format(now);
LocalDateTime now = LocalDateTime.now(ZoneId.of("GMT+2"));
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
context.put("myTimezone", "GMT+2");
@@ -178,15 +212,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatWithTimezoneAsExpression_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = Calendar.getInstance(TimeZone.getTimeZone("GMT+2")).getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(TimeZone.getTimeZone("GMT+2"));
String formatted = sdf.format(now);
LocalDateTime now = LocalDateTime.now(ZoneId.of("GMT+2"));
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
context.put("myTimezone", "GMT+2");
@@ -206,13 +238,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatCalendar() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Calendar calendar = Calendar.getInstance();
String formatted = new SimpleDateFormat(format).format(calendar.getTime());
String formatted = DateTimeFormatter.ofPattern(format).format(calendar.toInstant().atZone(ZoneId.systemDefault()));
context.put("myDate", calendar);
tag.setName("myDate");
@@ -227,13 +259,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatCalendar_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Calendar calendar = Calendar.getInstance();
String formatted = new SimpleDateFormat(format).format(calendar.getTime());
String formatted = DateTimeFormatter.ofPattern(format).format(calendar.toInstant().atZone(ZoneId.systemDefault()));
context.put("myDate", calendar);
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
@@ -251,13 +283,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatLong() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date date = new Date();
String formatted = new SimpleDateFormat(format).format(date);
String formatted = DateTimeFormatter.ofPattern(format).format(date.toInstant().atZone(ZoneId.systemDefault()));
// long
context.put("myDate", date.getTime());
@@ -273,13 +305,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatLong_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date date = new Date();
String formatted = new SimpleDateFormat(format).format(date);
String formatted = DateTimeFormatter.ofPattern(format).format(date.toInstant().atZone(ZoneId.systemDefault()));
// long
context.put("myDate", date.getTime());
@@ -298,7 +330,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatLocalDateTime() throws Exception {
@@ -332,7 +364,7 @@ public class DateTagTest extends AbstractTagTest {
public void testDefaultFormat() throws Exception {
Date now = new Date();
String formatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
ActionContext.getContext().getLocale()).format(now);
ActionContext.getContext().getLocale()).format(now);
context.put("myDate", now);
tag.setName("myDate");
@@ -346,13 +378,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testDefaultFormat_clearTagStateSet() throws Exception {
Date now = new Date();
String formatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
ActionContext.getContext().getLocale()).format(now);
ActionContext.getContext().getLocale()).format(now);
context.put("myDate", now);
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
@@ -369,13 +401,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatAndComponent() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setName("myDate");
@@ -388,7 +420,7 @@ public class DateTagTest extends AbstractTagTest {
org.apache.struts2.components.Date component = (org.apache.struts2.components.Date) tag.getComponent();
assertEquals("myDate", component.getName());
assertEquals(format, component.getFormat());
assertEquals(false, component.isNice());
assertFalse(component.isNice());
tag.doEndTag();
@@ -399,13 +431,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCustomFormatAndComponent_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
@@ -420,7 +452,7 @@ public class DateTagTest extends AbstractTagTest {
org.apache.struts2.components.Date component = (org.apache.struts2.components.Date) tag.getComponent();
assertEquals("myDate", component.getName());
assertEquals(format, component.getFormat());
assertEquals(false, component.isNice());
assertFalse(component.isNice());
tag.doEndTag();
@@ -432,13 +464,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testSetId() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setName("myDate");
@@ -454,13 +486,13 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testSetId_clearTagStateSet() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date now = new Date();
String formatted = new SimpleDateFormat(format).format(now);
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format).format(now);
context.put("myDate", now);
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
@@ -479,7 +511,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureNiceHour() throws Exception {
@@ -501,7 +533,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureNiceHour_clearTagStateSet() throws Exception {
@@ -526,7 +558,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testPastNiceHour() throws Exception {
@@ -548,7 +580,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testPastNiceHour_clearTagStateSet() throws Exception {
@@ -573,7 +605,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureNiceHourMinSec() throws Exception {
@@ -596,7 +628,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureNiceHourMinSec_clearTagStateSet() throws Exception {
@@ -622,7 +654,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testPastNiceHourMin() throws Exception {
@@ -645,7 +677,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testPastNiceHourMin_clearTagStateSet() throws Exception {
@@ -671,7 +703,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureLessOneMin() throws Exception {
@@ -693,7 +725,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureLessOneMin_clearTagStateSet() throws Exception {
@@ -718,7 +750,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureLessOneHour() throws Exception {
@@ -740,7 +772,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureLessOneHour_clearTagStateSet() throws Exception {
@@ -765,7 +797,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureLessOneYear() throws Exception {
@@ -787,7 +819,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureLessOneYear_clearTagStateSet() throws Exception {
@@ -812,7 +844,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureTwoYears() throws Exception {
@@ -838,7 +870,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testFutureTwoYears_clearTagStateSet() throws Exception {
@@ -867,7 +899,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testNoDateObjectInContext() throws Exception {
@@ -884,7 +916,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testNoDateObjectInContext_clearTagStateSet() throws Exception {
@@ -904,7 +936,7 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
/**
@@ -912,10 +944,8 @@ public class DateTagTest extends AbstractTagTest {
* since that tag does not have its own unit tests, and it also appears to be
* a broken tag. The code coverage tests can be moved if the tag is fixed, or
* removed if the tag is dropped.
*
* @throws Exception
*/
public void testDateTextFieldTag_artificialCoverageTest() throws Exception {
public void testDateTextFieldTag_artificialCoverageTest() throws JspException {
final String format = "yyyy/MM/dd hh:mm:ss";
DateTextFieldTag dateTextFieldTag = createDateTextFieldTag();
dateTextFieldTag.setFormat(format);
@@ -939,20 +969,40 @@ public class DateTagTest extends AbstractTagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(dateTextFieldTag, freshTag));
strutsBodyTagsAreReflectionEqual(dateTextFieldTag, freshTag));
}
public void testNewJava8Format() throws Exception {
String format = "EEEE MMMM dd, hh:mm a";
LocalDateTime now = LocalDateTime.now();
String formatted = DateTimeFormatter.ofPattern(format, ActionContext.getContext().getLocale()).format(now);
context.put("myDate", now);
tag.setName("myDate");
tag.setNice(false);
tag.setFormat(format);
tag.doStartTag();
tag.doEndTag();
assertEquals(formatted, writer.toString());
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
DateTag freshTag = new DateTag();
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
/**
* Utility method to create a new {@link DateTextFieldTag} instance for code coverage tests.
*
* <p>
* Note: There is no datetextfield.ftl template for the tag, so it does not appear that it can
* actually be used in practice. We can perform basic coverage tests from within this
* unit test class until the {@link DateTextFieldTag} is fixed or removed.
*
* actually be used in practice. We can perform basic coverage tests from within this
* unit test class until the {@link DateTextFieldTag} is fixed or removed.
*
* @return a basic {@link DateTextFieldTag} instance
* @throws Exception
*/
private DateTextFieldTag createDateTextFieldTag() throws Exception {
private DateTextFieldTag createDateTextFieldTag() {
DateTextFieldTag tag = new DateTextFieldTag();
tag.setPageContext(pageContext);
tag.setName("myDate");
@@ -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);
@@ -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;
@@ -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);
@@ -347,6 +347,7 @@ public class TextfieldTest extends AbstractUITagTest {
tag.setValue("%{foo}");
tag.setSize("10");
tag.setDynamicAttribute(null, "anotherAttr", "%{foo}");
tag.setDynamicAttribute(null, "secondAttr", "second_%{foo}");
tag.doStartTag();
tag.doEndTag();
@@ -373,6 +374,7 @@ public class TextfieldTest extends AbstractUITagTest {
tag.setValue("%{foo}");
tag.setSize("10");
tag.setDynamicAttribute(null, "anotherAttr", "%{foo}");
tag.setDynamicAttribute(null, "secondAttr", "second_%{foo}");
tag.doStartTag();
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
@@ -1,4 +1,4 @@
<tr>
<td class="tdLabel"><label for="myname" class="label">mylabel:</label></td>
<td class="tdInput"><input type="text" name="myname" size="10" value="%{1+1}" id="myname" anotherAttr="%{1+1}"/></td>
<td class="tdInput"><input type="text" name="myname" size="10" value="%{1+1}" id="myname" anotherAttr="%{1+1}" secondAttr="second_%{1+1}"/></td>
</tr>
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -18,4 +19,13 @@
* under the License.
*/
-->
<body>Type conversion meta data classes.</body>
<!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>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-async-plugin</artifactId>
+13 -7
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -44,11 +44,6 @@
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
@@ -60,6 +55,17 @@
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<!-- this library is excluded in the parent pom as it clashes with Easymock dependencies -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.2</version>
</dependency>
<!--
The Java EE API modules listed below are all marked @Deprecated(forRemoval=true), because they are scheduled
@@ -94,4 +100,4 @@
</dependencies>
</project>
</project>
@@ -20,17 +20,20 @@
*/
package org.apache.struts.beanvalidation.constraints.impl;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts.beanvalidation.constraints.FieldMatch;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {
private static final Logger LOG = LogManager.getLogger(FieldMatchValidator.class);
private String firstFieldName;
private String secondFieldName;
@@ -41,13 +44,23 @@ public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Obje
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
try {
final Object firstObj = PropertyUtils.getProperty(value, this.firstFieldName);
final Object secondObj = PropertyUtils.getProperty(value, this.secondFieldName);
final Object firstObj = readPropertyValue(value, this.firstFieldName);
final Object secondObj = readPropertyValue(value, this.secondFieldName);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
} catch (final Exception ex) {
LOG.info("Error while getting values from object", ex);
return false;
}
}
private Object readPropertyValue(Object bean, String propertyName) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
if (propertyName.equals(descriptor.getName())) {
return descriptor.getReadMethod().invoke(bean);
}
}
return null;
}
}
@@ -0,0 +1,84 @@
/*
* 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.
*/
package org.apache.struts.beanvalidation.constraints.impl;
import org.apache.struts.beanvalidation.constraints.FieldMatch;
import org.junit.Test;
import org.mockito.Mockito;
import javax.validation.ConstraintValidatorContext;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class FieldMatchValidatorTest {
@Test
public void matchingFields() {
// given
FieldMatchValidator validator = new FieldMatchValidator();
validator.initialize(FieldMatchTestBean.class.getAnnotation(FieldMatch.class));
ConstraintValidatorContext context = Mockito.mock(ConstraintValidatorContext.class);
// when
FieldMatchTestBean bean = new FieldMatchTestBean("12345678", "12345678");
boolean valid = validator.isValid(bean, context);
// then
assertTrue(valid);
}
@Test
public void notMatchingFields() {
// given
FieldMatchValidator validator = new FieldMatchValidator();
validator.initialize(FieldMatchTestBean.class.getAnnotation(FieldMatch.class));
ConstraintValidatorContext context = Mockito.mock(ConstraintValidatorContext.class);
// when
FieldMatchTestBean bean = new FieldMatchTestBean("12345678", "87654321");
boolean valid = validator.isValid(bean, context);
// then
assertFalse(valid);
}
@FieldMatch(first = "password", second = "repeatPassword")
public static class FieldMatchTestBean {
String password;
String repeatPassword;
public FieldMatchTestBean(String password, String repeatPassword) {
this.password = password;
this.repeatPassword = repeatPassword;
}
public String getPassword() {
return password;
}
public String getRepeatPassword() {
return repeatPassword;
}
}
}
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-cdi-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-config-browser-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-convention-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-dwr-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-embeddedjsp-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-gxp-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-jasperreports-plugin</artifactId>
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-javatemplates-plugin</artifactId>
@@ -28,7 +28,7 @@ import java.util.LinkedHashMap;
*/
public class Attributes extends LinkedHashMap<String, String> {
private static final long serialVersionUID = 4103241472140545630L;
private static final long serialVersionUID = 4103241472140545630L;
public Attributes add(String key, String value) {
return add(key, value, true);
@@ -74,15 +74,17 @@ public class Attributes extends LinkedHashMap<String, String> {
* @return this
*/
public Attributes addIfTrue(String attrName, Object paramValue) {
if (paramValue != null) {
if ((paramValue instanceof Boolean && ((Boolean) paramValue).booleanValue()) ||
(Boolean.valueOf(paramValue.toString()).booleanValue())) {
put(attrName, attrName);
}
if (paramValue != null && isTrue(paramValue)) {
put(attrName, attrName);
}
return this;
}
private boolean isTrue(Object paramValue) {
return (paramValue instanceof Boolean && (Boolean) paramValue)
|| (Boolean.parseBoolean(paramValue.toString()));
}
/**
* Add a key/value pair to the attributes, if the value is null, it will be set as an empty string.
* Value is html encoded.
@@ -22,14 +22,15 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
/**
* Default implementation of TagHandlerFactory
* Default implementation of TagHandlerFactory
*/
public class DefaultTagHandlerFactory implements TagHandlerFactory {
private static final Logger LOG = LogManager.getLogger(DefaultTagHandlerFactory.class);
private Class tagHandlerClass;
public DefaultTagHandlerFactory(Class tagHandlerClass) {
private static final Logger LOG = LogManager.getLogger(DefaultTagHandlerFactory.class);
private final Class<?> tagHandlerClass;
public DefaultTagHandlerFactory(Class<?> tagHandlerClass) {
this.tagHandlerClass = tagHandlerClass;
}
@@ -41,7 +42,7 @@ public class DefaultTagHandlerFactory implements TagHandlerFactory {
} catch (Exception e) {
LOG.error("Failed to instantiate tag handler class [{}]", tagHandlerClass.getName(), e);
}
return null;
}
@@ -37,16 +37,20 @@ public class AnchorHandler extends AbstractTagHandler implements TagGenerator {
Attributes attrs = new Attributes();
attrs.addIfExists("name", params.get("name"))
.addIfExists("id", params.get("id"))
.addIfExists("class", params.get("cssClass"))
.addIfExists("style", params.get("cssStyle"))
.addIfExists("href", params.get("href"), false)
.addIfExists("title", params.get("title"))
.addIfExists("tabindex", params.get("tabindex"));
.addIfExists("id", params.get("id"))
.addIfExists("class", params.get("cssClass"))
.addIfExists("style", params.get("cssStyle"))
.addIfExists("href", params.get("href"), false)
.addIfTrue("disabled", params.get("disabled"))
.addIfExists("title", params.get("title"))
.addIfExists("tabindex", params.get("tabindex"));
start("a", attrs);
String body = (String) params.get("body");
if (StringUtils.isNotEmpty(body))
characters(body, false);
Boolean escapeHtmlBody = (Boolean) params.get("escapeHtmlBody");
if (StringUtils.isNotEmpty(body)) {
characters(body, escapeHtmlBody);
}
end("a");
}
}
@@ -18,13 +18,14 @@
*/
package org.apache.struts2.views.java.simple;
import org.apache.struts2.views.java.Attributes;
import org.apache.struts2.views.java.TagGenerator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.struts2.views.java.Attributes;
import org.apache.struts2.views.java.TagGenerator;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
public class CheckboxHandler extends AbstractTagHandler implements TagGenerator {
public void generate() throws IOException {
@@ -35,29 +36,33 @@ public class CheckboxHandler extends AbstractTagHandler implements TagGenerator
String id = (String) params.get("id");
String name = (String) params.get("name");
Object disabled = params.get("disabled");
boolean submitUnchecked = Boolean.parseBoolean(Objects.toString(params.get("submitUnchecked"), "false"));
attrs.add("type", "checkbox")
.add("name", name)
.add("value", fieldValue)
.addIfTrue("checked", params.get("nameValue"))
.addIfTrue("readonly", params.get("readonly"))
.addIfTrue("disabled", disabled)
.addIfExists("tabindex", params.get("tabindex"))
.addIfExists("id", id)
.addIfExists("class", params.get("cssClass"))
.addIfExists("style", params.get("cssStyle"))
.addIfExists("title", params.get("title"));
.add("name", name)
.add("value", fieldValue)
.addIfTrue("checked", params.get("nameValue"))
.addIfTrue("readonly", params.get("readonly"))
.addIfTrue("disabled", disabled)
.addIfExists("tabindex", params.get("tabindex"))
.addIfExists("id", id)
.addIfExists("class", params.get("cssClass"))
.addIfExists("style", params.get("cssStyle"))
.addIfExists("title", params.get("title"));
start("input", attrs);
end("input");
//hidden input
attrs = new Attributes();
attrs.add("type", "hidden")
if (submitUnchecked) {
//hidden input
attrs = new Attributes();
attrs.add("type", "hidden")
.add("id", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(id)))
.add("name", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(name)))
.add("value", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(fieldValue)))
.addIfTrue("disabled", disabled);
start("input", attrs);
end("input");
start("input", attrs);
end("input");
}
}
}
@@ -40,9 +40,13 @@ public class LinkHandler extends AbstractTagHandler implements TagGenerator {
.addIfExists("referrerpolicy", params.get("referrerpolicy"))
.addIfExists("type", params.get("type"))
.addIfExists("as", params.get("as"))
.addIfExists("disabled", params.get("disabled"))
.addIfExists("title", params.get("title"));
// see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled
if ("stylesheet".equals(params.get("rel"))) {
attrs.addIfTrue("disabled", params.get("disabled"));
}
start("link", attrs);
end("link");
}
@@ -18,9 +18,9 @@
*/
package org.apache.struts2.views.java.simple;
import org.apache.struts2.views.java.TagGenerator;
import org.apache.struts2.views.java.Attributes;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.views.java.Attributes;
import org.apache.struts2.views.java.TagGenerator;
import java.io.IOException;
import java.util.Map;
@@ -34,12 +34,13 @@ public class ResetHandler extends AbstractTagHandler implements TagGenerator {
boolean isButton = "button".equals(params.get("type"));
attrs.addDefaultToEmpty("name", params.get("name"))
.add("type", "reset")
.addIfExists("value", params.get("nameValue"))
.addIfExists("tabindex", params.get("tabindex"))
.addIfExists("id", params.get("id"))
.addIfExists("class", params.get("cssClass"))
.addIfExists("style", params.get("cssStyle"));
.add("type", "reset")
.addIfExists("value", params.get("nameValue"))
.addIfTrue("disabled", params.get("disabled"))
.addIfExists("tabindex", params.get("tabindex"))
.addIfExists("id", params.get("id"))
.addIfExists("class", params.get("cssClass"))
.addIfExists("style", params.get("cssStyle"));
if (!isButton)
attrs.addIfExists("title", params.get("title"));
@@ -65,13 +65,13 @@ public class SimpleTheme extends DefaultTheme {
setName("simple");
}
private class FactoryList extends ArrayList<TagHandlerFactory> {
private static class FactoryList extends ArrayList<TagHandlerFactory> {
private static final long serialVersionUID = -1551895041394434032L;
public FactoryList(Class... classes) {
public FactoryList(Class<?>... classes) {
super();
for (Class cls : classes) {
for (Class<?> cls : classes) {
add(new DefaultTagHandlerFactory(cls));
}
add(new DefaultTagHandlerFactory(XHTMLTagSerializer.class));
@@ -73,6 +73,7 @@ public class SubmitHandler extends AbstractTagHandler implements TagGenerator {
public void generate() throws IOException {
Map<String, Object> params = context.getParameters();
String body = (String) params.get("body");
Boolean escapeHtmlBody = (Boolean) params.get("escapeHtmlBody");
String type = StringUtils.defaultString((String) params.get("type"), "input");
if ("button".equals(type)) {
@@ -81,16 +82,19 @@ public class SubmitHandler extends AbstractTagHandler implements TagGenerator {
characters(body, false);
else if (params.containsKey("label")) {
String label = (String) params.get("label");
if (StringUtils.isNotEmpty(label))
characters(label, false);
if (StringUtils.isNotEmpty(label)) {
characters(label, escapeHtmlBody);
}
}
end("button");
} else if ("image".equals(type)) {
if (StringUtils.isNotEmpty(body))
characters(body, false);
if (StringUtils.isNotEmpty(body)) {
characters(body, escapeHtmlBody);
}
end("input");
} else
} else {
end("input");
}
}
}
}
@@ -43,7 +43,7 @@ public class AnchorTest extends AbstractTest {
theme.renderTag(getTagName(), context);
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<a name='name_' id='id_' class='class' style='style' href='http://sometest.com?ab=10' title='title' tabindex='1'></a>");
String expected = s("<a name='name_' id='id_' class='class' style='style' href='http://sometest.com?ab=10' disabled='disabled' title='title' tabindex='1'></a>");
assertEquals(expected, output);
}
@@ -69,6 +69,42 @@ public class AnchorTest extends AbstractTest {
assertEquals(expected, output);
}
public void testEnableEscapeBody() {
tag.setName("name_");
tag.setHref("http://sometest.com?ab=10");
tag.setEscapeHtmlBody(true);
tag.evaluateParams();
map.putAll(tag.getParameters());
context.getParameters().put("body", s("<i class='i-image'/>"));
theme.renderTag(getTagName(), context);
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<a name='name_' id='name_' href='http://sometest.com?ab=10'>&lt;i class=&quot;i-image&quot;/&gt;</a>");
assertEquals(expected, output);
}
public void testDefaultDisabledEscapeBody() {
tag.setName("name_");
tag.setHref("http://sometest.com?ab=10");
//tag.setEscapeHtmlBody(true);
tag.evaluateParams();
map.putAll(tag.getParameters());
context.getParameters().put("body", s("<i class='i-image'/>"));
theme.renderTag(getTagName(), context);
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<a name='name_' id='name_' href='http://sometest.com?ab=10'><i class='i-image'/></a>");
assertEquals(expected, output);
}
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -29,7 +29,7 @@ public class CheckboxTest extends AbstractCommonAttributesTest {
public void testRenderCheckbox() {
tag.setName("name_");
tag.setDisabled("true");
tag.setDisabled("false");
tag.setTabindex("1");
tag.setId("id_");
tag.setCssClass("class");
@@ -41,20 +41,38 @@ public class CheckboxTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input type='checkbox' name='name_' value='xyz' tabindex='1' id='id_' class='class' style='style' title='title'></input><input type='hidden' id='__checkbox_id_' name='__checkbox_name_' value='__checkbox_xyz'></input>");
String expected = s("<input type='checkbox' name='name_' value='xyz' tabindex='1' id='id_' class='class' style='style' title='title'></input>");
assertEquals(expected, output);
}
public void testRenderUncheckCheckbox() {
tag.setName("name_");
tag.setDisabled("true");
tag.setTabindex("1");
tag.setId("id_");
tag.setCssClass("class");
tag.setCssStyle("style");
tag.setTitle("title");
tag.setFieldValue("xyz");
tag.setSubmitUnchecked("true");
tag.evaluateParams();
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input type='checkbox' name='name_' value='xyz' disabled='disabled' tabindex='1' id='id_' class='class' style='style' title='title'></input><input type='hidden' id='__checkbox_id_' name='__checkbox_name_' value='__checkbox_xyz' disabled='disabled'></input>");
assertEquals(expected, output);
}
public void testRenderCheckboxWithNameValue() {
tag.setName("name_");
tag.setValue("%{someValue}");
tag.setDisabled("true");
tag.evaluateParams();
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input type='checkbox' name='name_' value='true' checked='checked' id='name_'></input><input type='hidden' id='__checkbox_name_' name='__checkbox_name_' value='__checkbox_true'></input>");
String expected = s("<input type='checkbox' name='name_' value='true' checked='checked' id='name_'></input>");
assertEquals(expected, output);
}
@@ -43,7 +43,7 @@ public class FileTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input name='name' type='file' size='10' value='val1' accept='accept_' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
String expected = s("<input name='name' type='file' size='10' value='val1' disabled='disabled' accept='accept_' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
assertEquals(expected, output);
}
@@ -41,7 +41,7 @@ public class HiddenTest extends AbstractTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input name='name' type='hidden' value='val1' id='id1' class='class1' style='style1'></input>");
String expected = s("<input name='name' type='hidden' value='val1' disabled='disabled' id='id1' class='class1' style='style1'></input>");
assertEquals(expected, output);
}
@@ -31,7 +31,7 @@ public class LinkTest extends AbstractTest{
private static final String NONCE_VAL = "r4andom";
public void testRenderScriptTag() {
public void testRenderLinkTag() {
tag.setHref("testhref");
tag.setHreflang("test");
tag.setRel("module");
@@ -41,27 +41,60 @@ public class LinkTest extends AbstractTest{
tag.setCrossorigin("same-origin");
tag.setType("anonymous");
tag.setAs("test");
tag.setDisabled("disabled_");
tag.setDisabled("true");
tag.setTitle("test");
tag.evaluateParams();
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String s = writer.getBuffer().toString();
String output = writer.getBuffer().toString();
assertTrue("Incorrect href attribute for link tag", s.contains("href=\"testhref\""));
assertTrue("Incorrect hreflang attribute for link tag", s.contains("hreflang=\"test\""));
assertTrue("Incorrect rel attribute for link tag", s.contains("rel=\"module\""));
assertTrue("Incorrect media attribute for link tag", s.contains("media=\"foo\""));
assertTrue("Incorrect referrerpolicy attribute for link tag", s.contains("referrerpolicy=\"test\""));
assertTrue("Incorrect sizes attribute for link tag", s.contains("sizes=\"foo\""));
assertTrue("Incorrect crossorigin attribute for link tag", s.contains("crossorigin=\"same-origin\""));
assertTrue("Incorrect type attribute for link tag", s.contains("type=\"anonymous\""));
assertTrue("Incorrect as attribute for link tag", s.contains("as=\"test\""));
assertTrue("Non-existent disabled attribute for link tag", s.contains("disabled=\"disabled_\""));
assertTrue("Incorrect title attribute for link tag", s.contains("title=\"test\""));
assertTrue("Incorrect nonce attribute for link tag", s.contains("nonce=\"" + NONCE_VAL+"\""));
assertTrue("Incorrect href attribute for link tag", output.contains(s("href='testhref'")));
assertTrue("Incorrect hreflang attribute for link tag", output.contains(s("hreflang='test'")));
assertTrue("Incorrect rel attribute for link tag", output.contains(s("rel='module'")));
assertTrue("Incorrect media attribute for link tag", output.contains(s("media='foo'")));
assertTrue("Incorrect referrerpolicy attribute for link tag", output.contains(s("referrerpolicy='test'")));
assertTrue("Incorrect sizes attribute for link tag", output.contains(s("sizes='foo'")));
assertTrue("Incorrect crossorigin attribute for link tag", output.contains(s("crossorigin='same-origin'")));
assertTrue("Incorrect type attribute for link tag", output.contains(s("type='anonymous'")));
assertTrue("Incorrect as attribute for link tag", output.contains(s("as='test'")));
assertFalse("Non-existent disabled attribute for link tag", output.contains(s("disabled='disabled'")));
assertTrue("Incorrect title attribute for link tag", output.contains(s("title='test'")));
assertTrue("Incorrect nonce attribute for link tag", output.contains(s("nonce='" + NONCE_VAL+"'")));
}
public void testRenderLinkTagAsStylesheet() {
tag.setHref("testhref");
tag.setHreflang("test");
tag.setRel("stylesheet");
tag.setMedia("foo");
tag.setReferrerpolicy("test");
tag.setSizes("foo");
tag.setCrossorigin("same-origin");
tag.setType("anonymous");
tag.setAs("test");
tag.setDisabled("true");
tag.setTitle("test");
tag.evaluateParams();
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
assertTrue("Incorrect href attribute for link tag", output.contains(s("href='testhref'")));
assertTrue("Incorrect hreflang attribute for link tag", output.contains(s("hreflang='test'")));
assertTrue("Incorrect rel attribute for link tag", output.contains(s("rel='stylesheet'")));
assertTrue("Incorrect media attribute for link tag", output.contains(s("media='foo'")));
assertTrue("Incorrect referrerpolicy attribute for link tag", output.contains(s("referrerpolicy='test'")));
assertTrue("Incorrect sizes attribute for link tag", output.contains(s("sizes='foo'")));
assertTrue("Incorrect crossorigin attribute for link tag", output.contains(s("crossorigin='same-origin'")));
assertTrue("Incorrect type attribute for link tag", output.contains(s("type='anonymous'")));
assertTrue("Incorrect as attribute for link tag", output.contains(s("as='test'")));
assertTrue("Incorrect disabled attribute for link tag", output.contains(s("disabled='disabled'")));
assertTrue("Incorrect title attribute for link tag", output.contains(s("title='test'")));
assertTrue("Incorrect nonce attribute for link tag", output.contains(s("nonce='" + NONCE_VAL+"'")));
}
@Override
protected UIBean getUIBean() throws Exception {
return tag;
@@ -24,11 +24,10 @@ import org.apache.struts2.components.Password;
import org.apache.struts2.components.UIBean;
public class PasswordTest extends AbstractCommonAttributesTest {
private Password tag;
private boolean showPassword;
public void testRenderPassword() throws Exception {
this.showPassword = false;
super.setUp();
this.tag = new Password(stack, request, response);
@@ -47,12 +46,11 @@ public class PasswordTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input name='name' type='password' size='10' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
String expected = s("<input name='name' type='password' size='10' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
assertEquals(expected, output);
}
public void testRenderPasswordShowIt() throws Exception {
this.showPassword = true;
super.setUp();
this.tag = new Password(stack, request, response);
@@ -71,7 +69,7 @@ public class PasswordTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input value='val1' name='name' type='password' size='10' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
String expected = s("<input value='val1' name='name' type='password' size='10' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
assertEquals(expected, output);
}
@@ -45,7 +45,7 @@ public class SelectTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<select name='name_' size='10' tabindex='1' id='id_' class='class' style='style' title='title'></select>");
String expected = s("<select name='name_' size='10' disabled='disabled' tabindex='1' id='id_' class='class' style='style' title='title'></select>");
assertEquals(expected, output);
}
@@ -47,7 +47,7 @@ public class SubmitTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<button name='name' type='submit' value='val1' tabindex='1' id='id1' class='class1' style='style1'><span>hey hey hey, here I go now</span></button>");
String expected = s("<button name='name' type='submit' value='val1' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1'><span>hey hey hey, here I go now</span></button>");
assertEquals(expected, output);
}
@@ -69,7 +69,7 @@ public class SubmitTest extends AbstractCommonAttributesTest {
theme.renderTag(getTagName(), context);
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<button name='name' type='submit' value='val1' tabindex='1' id='id1' class='class1' style='style1'>Just as soon as I belong, than its time I disappear</button>");
String expected = s("<button name='name' type='submit' value='val1' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1'>Just as soon as I belong, than its time I disappear</button>");
assertEquals(expected, output);
}
@@ -91,7 +91,7 @@ public class SubmitTest extends AbstractCommonAttributesTest {
theme.renderTag(getTagName(), context);
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<input name='name' type='submit' value='val1' tabindex='1' id='id1' class='class1' style='style1'></input>");
String expected = s("<input name='name' type='submit' value='val1' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1'></input>");
assertEquals(expected, output);
}
@@ -112,7 +112,7 @@ public class SubmitTest extends AbstractCommonAttributesTest {
theme.renderTag(getTagName(), context);
theme.renderTag(getTagName() + "-close", context);
String output = writer.getBuffer().toString();
String expected = s("<input name='name' type='submit' value='val1' tabindex='1' id='id1' class='class1' style='style1'></input>");
String expected = s("<input name='name' type='submit' value='val1' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1'></input>");
assertEquals(expected, output);
}
@@ -44,7 +44,7 @@ public class TextAreaTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<textarea name='name' cols='2' rows='1' tabindex='1' id='id1' class='class1' style='style1' title='title'>val1</textarea>");
String expected = s("<textarea name='name' cols='2' rows='1' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1' title='title'>val1</textarea>");
assertEquals(expected, output);
}
@@ -63,7 +63,7 @@ public class TextAreaTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<textarea name='' cols='' rows='' tabindex='1' id='id1' class='class1' style='style1' title='title'>val1</textarea>");
String expected = s("<textarea name='' cols='' rows='' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1' title='title'>val1</textarea>");
assertEquals(expected, output);
}
@@ -44,7 +44,7 @@ public class TextFieldTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input type='text' name='name' size='10' maxlength='11' value='val1' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
String expected = s("<input type='text' name='name' size='10' maxlength='11' value='val1' disabled='disabled' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
assertEquals(expected, output);
}
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-jfreechart-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-json-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.6-SNAPSHOT</version>
<version>6.0.0-SNAPSHOT</version>
</parent>
<artifactId>struts2-junit-plugin</artifactId>

Some files were not shown because too many files have changed in this diff Show More