You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2021/01/11 06:43:45 UTC

[struts] branch WW-4799-conversion-format updated (81fd1df -> 68648fe)

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

lukaszlenart pushed a change to branch WW-4799-conversion-format
in repository https://gitbox.apache.org/repos/asf/struts.git.


    omit 81fd1df  WW-4799 Adding struts.date.format as a conversion format for DateConverter
     new 68648fe  WW-4799 Adding struts.date.format as a conversion format for DateConverter

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

 * -- * -- B -- O -- O -- O   (81fd1df)
            \
             N -- N -- N   refs/heads/WW-4799-conversion-format (68648fe)

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

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

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


Summary of changes:
 .../opensymphony/xwork2/DefaultActionProxy.java    |   6 +-
 .../xwork2/conversion/impl/DateConverter.java      |  26 ++-
 .../xwork2/conversion/impl/DateConverterTest.java  | 187 +++++++++++----------
 .../conversion/impl/XWorkBasicConverterTest.java   |  96 +++++++----
 .../com/opensymphony/xwork2/ognl/OgnlUtilTest.java |  21 +--
 .../validator/SimpleActionValidationTest.java      |  18 +-
 6 files changed, 207 insertions(+), 147 deletions(-)


[struts] 01/01: WW-4799 Adding struts.date.format as a conversion format for DateConverter

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-4799-conversion-format
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 68648fe3a2b36afa2cb6c632b0754b866511109c
Author: Cabasson, Denis - CoSD/DSCo <de...@statcan.gc.ca>
AuthorDate: Mon Jun 12 16:26:02 2017 -0400

    WW-4799 Adding struts.date.format as a conversion format for DateConverter
---
 .../opensymphony/xwork2/DefaultActionProxy.java    |   6 +-
 .../xwork2/conversion/impl/DateConverter.java      |  77 ++++++++-
 .../com/opensymphony/xwork2/StubTextProvider.java  |  96 +++++++++++
 .../xwork2/conversion/impl/DateConverterTest.java  | 187 +++++++++++----------
 .../conversion/impl/XWorkBasicConverterTest.java   |  96 +++++++----
 .../xwork2/conversion/impl/XWorkConverterTest.java |  27 +++
 .../com/opensymphony/xwork2/ognl/OgnlUtilTest.java |  21 +--
 .../validator/SimpleActionValidationTest.java      |  18 +-
 8 files changed, 384 insertions(+), 144 deletions(-)

diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java
index 678a830..4d73813 100644
--- a/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java
@@ -147,17 +147,13 @@ public class DefaultActionProxy implements ActionProxy, Serializable {
         ActionContext nestedContext = ActionContext.getContext();
         ActionContext.bind(invocation.getInvocationContext());
 
-        String retCode = null;
-
         try {
-            retCode = invocation.invoke();
+            return invocation.invoke();
         } finally {
             if (cleanupContext) {
                 ActionContext.bind(nestedContext);
             }
         }
-
-        return retCode;
     }
 
 
diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
index 749b08b..99c1e2f 100644
--- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
+++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
@@ -18,7 +18,12 @@
  */
 package com.opensymphony.xwork2.conversion.impl;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.struts2.conversion.TypeConversionException;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.TextProvider;
+import com.opensymphony.xwork2.util.ValueStack;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Member;
@@ -31,11 +36,13 @@ import java.util.Map;
 
 public class DateConverter extends DefaultTypeConverter {
 
+    private final static Logger LOG = LogManager.getLogger(DateConverter.class);
+
     @Override
     public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
         Date result = null;
 
-        if (value instanceof String && value != null && ((String) value).length() > 0) {
+        if (value instanceof String && ((String) value).length() > 0) {
             String sa = (String) value;
             Locale locale = getLocale(context);
 
@@ -66,7 +73,8 @@ public class DateConverter extends DefaultTypeConverter {
                 }
             } else if (java.util.Date.class == toType) {
                 Date check;
-                DateFormat[] dfs = getDateFormats(locale);
+                DateFormat[] dfs = getDateFormats(ActionContext.of(context), locale);
+
                 for (DateFormat df1 : dfs) {
                     try {
                         check = df1.parse(sa);
@@ -87,7 +95,7 @@ public class DateConverter extends DefaultTypeConverter {
                 result = df.parse(sa);
                 if (!(Date.class == toType)) {
                     try {
-                        Constructor constructor = toType.getConstructor(new Class[]{long.class});
+                        Constructor<?> constructor = toType.getConstructor(new Class[]{long.class});
                         return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
                     } catch (Exception e) {
                         throw new TypeConversionException("Couldn't create class " + toType + " using default (long) constructor", e);
@@ -102,7 +110,44 @@ public class DateConverter extends DefaultTypeConverter {
         return result;
     }
 
-    private DateFormat[] getDateFormats(Locale locale) {
+    /**
+     * The user defined global date format,
+     * see {@link org.apache.struts2.components.Date#DATETAG_PROPERTY}
+     *
+     * @param context current ActionContext
+     * @param locale current Locale to convert to
+     * @return defined global format
+     */
+    protected DateFormat getGlobalDateFormat(ActionContext context, Locale locale) {
+        final String dateTagProperty = org.apache.struts2.components.Date.DATETAG_PROPERTY;
+        SimpleDateFormat globalDateFormat = null;
+
+        final TextProvider tp = findProviderInStack(context.getValueStack());
+
+        if (tp != null) {
+            String globalFormat = tp.getText(dateTagProperty);
+            // if tp.getText can not find the property then the returned string
+            // is the same as input = DATETAG_PROPERTY
+            if (globalFormat != null && !dateTagProperty.equals(globalFormat)) {
+                LOG.debug("Found \"{}\" as \"{}\"", dateTagProperty, globalFormat);
+                globalDateFormat = new SimpleDateFormat(globalFormat, locale);
+            } else {
+                LOG.debug("\"{}\" has not been defined, ignoring it", dateTagProperty);
+            }
+        }
+
+        return globalDateFormat;
+    }
+
+    /**
+     * Retrieves the list of date formats to be used when converting dates
+     * @param context the current ActionContext
+     * @param locale the current locale of the action
+     * @return a list of DateFormat to be used for date conversion
+     */
+    private DateFormat[] getDateFormats(ActionContext context, Locale locale) {
+        DateFormat globalDateFormat = getGlobalDateFormat(context, locale);
+
         DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
         DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
         DateFormat dt3 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
@@ -114,7 +159,29 @@ public class DateConverter extends DefaultTypeConverter {
         DateFormat rfc3339         = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
         DateFormat rfc3339dateOnly = new SimpleDateFormat("yyyy-MM-dd");
 
-        return new DateFormat[]{dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
+        final DateFormat[] dateFormats;
+
+        if (globalDateFormat == null) {
+            dateFormats = new DateFormat[]{dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
+        } else {
+            dateFormats = new DateFormat[]{globalDateFormat, dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
+        }
+
+        return dateFormats;
+    }
+
+    private TextProvider findProviderInStack(ValueStack stack) {
+        // TODO: ValueStack will never be null, this is just a workaround for tests
+        if (stack == null) {
+            LOG.warn("ValueStack is null, won't be able to find TextProvider!");
+            return null;
+        }
+        for (Object o : stack.getRoot()) {
+            if (o instanceof TextProvider) {
+                return (TextProvider) o;
+            }
+        }
+        return null;
     }
 
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/StubTextProvider.java b/core/src/test/java/com/opensymphony/xwork2/StubTextProvider.java
new file mode 100644
index 0000000..bc9b95c
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/StubTextProvider.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.util.ValueStack;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+public class StubTextProvider implements TextProvider {
+
+    private final Map<String, String> map;
+
+    public StubTextProvider(final Map<String, String> map) {
+        this.map = map;
+    }
+
+    @Override
+    public boolean hasKey(final String key) {
+        return map.containsKey(key);
+    }
+
+    @Override
+    public String getText(final String key) {
+        return map.get(key);
+    }
+
+    @Override
+    public String getText(final String key, final String defaultValue) {
+        final String text = this.getText(key);
+        return text == null? defaultValue : text;
+    }
+
+    @Override
+    public String getText(final String key, final String defaultValue, final String obj) {
+        return this.getText(key, defaultValue);
+    }
+
+    @Override
+    public String getText(final String key, final List<?> args) {
+        return this.getText(key);
+    }
+
+    @Override
+    public String getText(final String key, final String[] args) {
+        return this.getText(key);
+    }
+
+    @Override
+    public String getText(final String key, final String defaultValue, final List<?> args) {
+        return this.getText(key);
+    }
+
+    @Override
+    public String getText(final String key, final String defaultValue, final String[] args) {
+        return this.getText(key);
+    }
+
+    @Override
+    public String getText(final String key, final String defaultValue, final List<?> args, final ValueStack stack) {
+        return this.getText(key, defaultValue);
+    }
+
+    @Override
+    public String getText(final String key, final String defaultValue, final String[] args, final ValueStack stack) {
+        return this.getText(key, defaultValue);
+    }
+
+    @Override
+    public ResourceBundle getTexts(final String bundleName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ResourceBundle getTexts() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java
index 157e6d8..7749583 100644
--- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java
@@ -19,8 +19,11 @@
 package com.opensymphony.xwork2.conversion.impl;
 
 import com.opensymphony.xwork2.ActionContext;
-import org.apache.struts2.conversion.TypeConversionException;
+import com.opensymphony.xwork2.StubTextProvider;
+import com.opensymphony.xwork2.StubValueStack;
+import com.opensymphony.xwork2.util.ValueStack;
 import org.apache.struts2.StrutsInternalTestCase;
+import org.apache.struts2.conversion.TypeConversionException;
 
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -31,88 +34,102 @@ import java.util.Locale;
 import java.util.Map;
 
 public class DateConverterTest extends StrutsInternalTestCase {
-	
-	private String INPUT_TIME_STAMP_STR;
-	private String INPUT_WHEN_LONG_CONSTRUCTOR_STR;
-	private Locale mxLocale = new Locale("es_MX", "MX");
-	private final static String RES_TIME_STAMP_STR = "2020-03-20 00:00:00.0";
-	private final static String TIME_01_59_10 = "01:59:10 AM";
-	private final static String DATE_STR = "2020-03-20";
-	private final static String DATE_CONVERTED = "Fri Mar 20 00:00:00";
-	private final static String INVALID_DATE = "99/99/2010";
-	private final static String MESSAGE_PARSE_ERROR = "Could not parse date";
-	private final static String MESSAGE_DEFAULT_CONSTRUCTOR_ERROR = "Couldn't create class null using default (long) constructor";
-	
-	public void testSqlTimeType() {
-		DateConverter converter = new DateConverter();
-		
-		Map<String, Object> context = new HashMap<>();
-		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
-		
-		Object value = converter.convertValue(context, null, null, null, TIME_01_59_10, Time.class);
-		assertEquals("01:59:10", value.toString());
-	}
-	
-	public void testSqlTimestampType() {
-		DateConverter converter = new DateConverter();
-		Map<String, Object> context = new HashMap<>();
-		context.put(ActionContext.LOCALE, mxLocale);
-		
-		Object value = converter.convertValue(context, null, null, null, INPUT_TIME_STAMP_STR, Timestamp.class);
-		assertEquals(RES_TIME_STAMP_STR, value.toString());
-	}
-	
-	public void testDateType() {
-		DateConverter converter = new DateConverter();
-		
-		Map<String, Object> context = new HashMap<>();
-		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
-		
-		Object value = converter.convertValue(context, null, null, null, DATE_STR, Date.class);
-		assertTrue(((Date) value).toString().startsWith(DATE_CONVERTED));
-	}
-	
-	public void testTypeConversionExceptionWhenParseError() {
-		DateConverter converter = new DateConverter();
-		
-		Map<String, Object> context = new HashMap<>();
-		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
-		
-		try {
-			Object value = converter.convertValue(context, null, null, null, INVALID_DATE, Date.class);
-			fail("TypeConversionException expected - Conversion error occurred");
-		} catch (Exception ex) {
-			assertEquals(TypeConversionException.class, ex.getClass());
-			assertEquals(MESSAGE_PARSE_ERROR, ex.getMessage());
-		}
-	}
-	
-	public void testTypeConversionExceptionWhenUsingLongConstructor() {
-		DateConverter converter = new DateConverter();
-		
-		Map<String, Object> context = new HashMap<>();
-		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
-		
-		try {
-			Object value = converter.convertValue(context, null, null, null, INPUT_WHEN_LONG_CONSTRUCTOR_STR, null);
-			fail("TypeConversionException expected - Error using default (long) constructor");
-		} catch (Exception ex) {
-			assertEquals(TypeConversionException.class, ex.getClass());
-			assertEquals(MESSAGE_DEFAULT_CONSTRUCTOR_ERROR, ex.getMessage());
-		}
-	}
-	
-	@Override
-	protected void setUp() {
-		//Due to JEP 252: Use CLDR Locale Data by Default
-		DateFormat dFormat = DateFormat.getDateInstance(DateFormat.SHORT, mxLocale);
-		if(dFormat.format(new Date()).contains("-")){ 			// Format when Java 9 or greater
-			INPUT_TIME_STAMP_STR = "2020-03-20 00:00:00.000";
-			INPUT_WHEN_LONG_CONSTRUCTOR_STR = "2020-03-20";
-		}else{ 																							// Format when Java 8 or lower
-			INPUT_TIME_STAMP_STR = "03/20/2020 00:00:00.000";
-			INPUT_WHEN_LONG_CONSTRUCTOR_STR = "03/31/20";
-		}
-	}
-	
+
+    private String INPUT_TIME_STAMP_STR;
+    private String INPUT_WHEN_LONG_CONSTRUCTOR_STR;
+    private final Locale mxLocale = new Locale("es_MX", "MX");
+    private final static String RES_TIME_STAMP_STR = "2020-03-20 00:00:00.0";
+    private final static String TIME_01_59_10 = "01:59:10 AM";
+    private final static String DATE_STR = "2020-03-20";
+    private final static String DATE_CONVERTED = "Fri Mar 20 00:00:00";
+    private final static String INVALID_DATE = "99/99/2010";
+    private final static String MESSAGE_PARSE_ERROR = "Could not parse date";
+    private final static String MESSAGE_DEFAULT_CONSTRUCTOR_ERROR = "Couldn't create class null using default (long) constructor";
+
+    public void testSqlTimeType() {
+        DateConverter converter = new DateConverter();
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(mxLocale);
+
+        Object value = converter.convertValue(context.getContextMap(), null, null, null, TIME_01_59_10, Time.class);
+        assertEquals("01:59:10", value.toString());
+    }
+
+    public void testSqlTimestampType() {
+        DateConverter converter = new DateConverter();
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(mxLocale);
+
+        Object value = converter.convertValue(context.getContextMap(), null, null, null, INPUT_TIME_STAMP_STR, Timestamp.class);
+        assertEquals(RES_TIME_STAMP_STR, value.toString());
+    }
+
+    public void testDateType() {
+        DateConverter converter = new DateConverter();
+
+        Map<String, String> map = new HashMap<>();
+        map.put(org.apache.struts2.components.Date.DATETAG_PROPERTY, "yyyy-MM-dd");
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(map));
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(new Locale("es_MX", "MX"))
+            .withValueStack(stack);
+
+        Object value = converter.convertValue(context.getContextMap(), null, null, null, DATE_STR, Date.class);
+        assertTrue(value.toString().startsWith(DATE_CONVERTED));
+    }
+
+    public void testTypeConversionExceptionWhenParseError() {
+        DateConverter converter = new DateConverter();
+
+        Map<String, String> map = new HashMap<>();
+        map.put(org.apache.struts2.components.Date.DATETAG_PROPERTY, "yyyy-MM-dd");
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(map));
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(new Locale("es_MX", "MX"))
+            .withValueStack(stack);
+
+        try {
+            converter.convertValue(context.getContextMap(), null, null, null, INVALID_DATE, Date.class);
+            fail("TypeConversionException expected - Conversion error occurred");
+        } catch (Exception ex) {
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertEquals(MESSAGE_PARSE_ERROR, ex.getMessage());
+        }
+    }
+
+    public void testTypeConversionExceptionWhenUsingLongConstructor() {
+        DateConverter converter = new DateConverter();
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(mxLocale);
+
+        try {
+            converter.convertValue(context.getContextMap(), null, null, null, INPUT_WHEN_LONG_CONSTRUCTOR_STR, null);
+            fail("TypeConversionException expected - Error using default (long) constructor");
+        } catch (Exception ex) {
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertEquals(MESSAGE_DEFAULT_CONSTRUCTOR_ERROR, ex.getMessage());
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        //Due to JEP 252: Use CLDR Locale Data by Default
+        DateFormat dFormat = DateFormat.getDateInstance(DateFormat.SHORT, mxLocale);
+        if (dFormat.format(new Date()).contains("-")) {            // Format when Java 9 or greater
+            INPUT_TIME_STAMP_STR = "2020-03-20 00:00:00.000";
+            INPUT_WHEN_LONG_CONSTRUCTOR_STR = "2020-03-20";
+        } else {// Format when Java 8 or lower
+            INPUT_TIME_STAMP_STR = "03/20/2020 00:00:00.000";
+            INPUT_WHEN_LONG_CONSTRUCTOR_STR = "03/31/20";
+        }
+    }
+
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
index 4209da1..a1fb332 100644
--- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
@@ -19,7 +19,10 @@
 package com.opensymphony.xwork2.conversion.impl;
 
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.StubTextProvider;
+import com.opensymphony.xwork2.StubValueStack;
 import com.opensymphony.xwork2.XWorkTestCase;
+import com.opensymphony.xwork2.util.ValueStack;
 import org.apache.struts2.conversion.TypeConversionException;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.test.annotations.Person;
@@ -50,51 +53,80 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
     // object -> return null when empty string is passed
 
     public void testDateConversionWithEmptyValue() {
-        Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "", Date.class);
+        Object convertedObject = basicConverter.convertValue(new HashMap<>(), null, null, null, "", Date.class);
         // we must not get StrutsException as that will caused a conversion error
         assertNull(convertedObject);
     }
 
-    public void testDateConversionWithInvalidValue() throws Exception {
+    public void testDateConversionWithInvalidValue() {
+        Map<String, String> map = new HashMap<>();
+        map.put(org.apache.struts2.components.Date.DATETAG_PROPERTY, "yyyy-MM-dd");
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(map));
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(new Locale("es_MX", "MX"))
+            .withValueStack(stack);
+
         try {
-            basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "asdsd", Date.class);
+            basicConverter.convertValue(context.getContextMap(), null, null, null, "asdsd", Date.class);
             fail("StrutsException expected - conversion error occurred");
         } catch (StrutsException e) {
-            // we MUST get this exception as this is a conversion error
+            assertEquals("Could not parse date", e.getMessage());
         }
     }
 
-    public void testDateWithLocalePoland() throws Exception {
+    public void testDateWithLocalePoland() {
+        Map<String, String> map = new HashMap<>();
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(map));
 
         Locale locale = new Locale("pl", "PL");
-        Map<String, Object> context = createContextWithLocale(locale);
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(locale)
+            .withValueStack(stack);
 
         String reference = "2009-01-09";
-        Object convertedObject = basicConverter.convertValue(context, null, null, null, reference, Date.class);
+        Object convertedObject = basicConverter.convertValue(context.getContextMap(), null, null, null, reference, Date.class);
 
         assertNotNull(convertedObject);
 
         compareDates(locale, convertedObject);
     }
 
-    public void testDateWithLocaleFrance() throws Exception {
+    public void testDateWithLocaleFrance() {
+        Map<String, String> map = new HashMap<>();
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(map));
+
         Locale locale = new Locale("fr", "FR");
-        Map<String, Object> context = createContextWithLocale(locale);
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(locale)
+            .withValueStack(stack);
 
         String reference = "09/01/2009";
-        Object convertedObject = basicConverter.convertValue(context, null, null, null, reference, Date.class);
+        Object convertedObject = basicConverter.convertValue(context.getContextMap(), null, null, null, reference, Date.class);
 
         assertNotNull(convertedObject);
 
         compareDates(locale, convertedObject);
     }
 
-    public void testDateWithLocaleUK() throws Exception {
+    public void testDateWithLocaleUK() {
+        Map<String, String> map = new HashMap<>();
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(map));
+
         Locale locale = new Locale("en", "US");
-        Map<String, Object> context = createContextWithLocale(locale);
+
+        ActionContext context = ActionContext.of(new HashMap<>())
+            .withLocale(locale)
+            .withValueStack(stack);
 
         String reference = "01/09/2009";
-        Object convertedObject = basicConverter.convertValue(context, null, null, null, reference, Date.class);
+        Object convertedObject = basicConverter.convertValue(context.getContextMap(), null, null, null, reference, Date.class);
 
         assertNotNull(convertedObject);
 
@@ -118,21 +150,21 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         assertEquals(df.format(cal.getTime()), df.format(convertedObject));
     }
 
-    public void testEmptyArrayConversion() throws Exception {
-        Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, new Object[]{}, Object[].class);
+    public void testEmptyArrayConversion() {
+        Object convertedObject = basicConverter.convertValue(new HashMap<>(), null, null, null, new Object[]{}, Object[].class);
         // we must not get StrutsException as that will caused a conversion error
         assertEquals(Object[].class, convertedObject.getClass());
         Object[] obj = (Object[]) convertedObject;
         assertEquals(0, obj.length);
     }
 
-    public void testNullArrayConversion() throws Exception {
-        Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, null, Object[].class);
+    public void testNullArrayConversion() {
+        Object convertedObject = basicConverter.convertValue(new HashMap<>(), null, null, null, null, Object[].class);
         // we must not get StrutsException as that will caused a conversion error
         assertNull(convertedObject);
     }
 
-    public void testXW490ConvertStringToDouble() throws Exception {
+    public void testXW490ConvertStringToDouble() {
         Locale locale = new Locale("DA"); // let's use a not common locale such as Denmark
         Map<String, Object> context = createContextWithLocale(locale);
 
@@ -144,7 +176,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         assertEquals(123.99d, value, 0.001d);
     }
 
-    public void testXW49ConvertDoubleToString() throws Exception {
+    public void testXW49ConvertDoubleToString() {
         Locale locale = new Locale("DA"); // let's use a not common locale such as Denmark
         Map<String, Object> context = createContextWithLocale(locale);
 
@@ -202,26 +234,26 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         assertEquals(1.46464989f, value);
     }
 
-    public void testNegativeFloatValue() throws Exception {
+    public void testNegativeFloatValue() {
         Object convertedObject = basicConverter.convertValue("-94.1231233", Float.class);
         assertTrue(convertedObject instanceof Float);
         assertEquals(-94.1231233f, (Float) convertedObject, 0.0001);
     }
 
-    public void testPositiveFloatValue() throws Exception {
+    public void testPositiveFloatValue() {
         Object convertedObject = basicConverter.convertValue("94.1231233", Float.class);
         assertTrue(convertedObject instanceof Float);
         assertEquals(94.1231233f, (Float) convertedObject, 0.0001);
     }
 
 
-    public void testNegativeDoubleValue() throws Exception {
+    public void testNegativeDoubleValue() {
         Object convertedObject = basicConverter.convertValue("-94.1231233", Double.class);
         assertTrue(convertedObject instanceof Double);
         assertEquals(-94.1231233d, (Double) convertedObject, 0.0001);
     }
 
-    public void testPositiveDoubleValue() throws Exception {
+    public void testPositiveDoubleValue() {
         Object convertedObject = basicConverter.convertValue("94.1231233", Double.class);
         assertTrue(convertedObject instanceof Double);
         assertEquals(94.1231233d, (Double) convertedObject, 0.0001);
@@ -278,7 +310,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         assertEquals(BigDecimal.valueOf(12345.67890), convertedObject);
     }
 
-    public void testNestedEnumValue() throws Exception {
+    public void testNestedEnumValue() {
         Object convertedObject = basicConverter.convertValue(ParentClass.NestedEnum.TEST.name(), ParentClass.NestedEnum.class);
         assertTrue(convertedObject instanceof ParentClass.NestedEnum);
         assertEquals(ParentClass.NestedEnum.TEST, convertedObject);
@@ -288,13 +320,13 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         Map<String, Object> context = new HashMap<>();
         String s = "names";
         Object value = new Person[0];
-        Class toType = String.class;
+        Class<?> toType = String.class;
         basicConverter.convertValue(context, value, null, s, value, toType);
     }
     
     public void testExceptionWhenCantCreateTypeFromValue() {
         try{
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, 4, Date.class);
+            basicConverter.convertValue(new HashMap<>(), null, null, null, 4, Date.class);
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
@@ -304,7 +336,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
     
     public void testExceptionInDoConvertToClass() {
         try{
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", Class.class);
+            basicConverter.convertValue(new HashMap<>(), null, null, null, "Foo", Class.class);
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
@@ -315,7 +347,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         try{
             Mockito.when(mockedContainer.getInstanceNames(CollectionConverter.class)).thenReturn(null);
             basicConverter.setContainer(mockedContainer);
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", ArrayList.class);
+            basicConverter.convertValue(new HashMap<>(), null, null, null, "Foo", ArrayList.class);
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
@@ -328,7 +360,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
             int[] arrayInt = new int[1];
             Mockito.when(mockedContainer.getInstanceNames(ArrayConverter.class)).thenReturn(null);
             basicConverter.setContainer(mockedContainer);
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", arrayInt.getClass());
+            basicConverter.convertValue(new HashMap<>(), null, null, null, "Foo", arrayInt.getClass());
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
@@ -340,7 +372,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         try{
             Mockito.when(mockedContainer.getInstanceNames(DateConverter.class)).thenReturn(null);
             basicConverter.setContainer(mockedContainer);
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", Date.class);
+            basicConverter.convertValue(new HashMap<>(), null, null, null, "Foo", Date.class);
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
@@ -352,7 +384,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         try{
             Mockito.when(mockedContainer.getInstanceNames(NumberConverter.class)).thenReturn(null);
             basicConverter.setContainer(mockedContainer);
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", int.class);
+            basicConverter.convertValue(new HashMap<>(), null, null, null, "Foo", int.class);
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
@@ -364,7 +396,7 @@ public class XWorkBasicConverterTest extends XWorkTestCase {
         try{
             Mockito.when(mockedContainer.getInstanceNames(StringConverter.class)).thenReturn(null);
             basicConverter.setContainer(mockedContainer);
-            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, 1, String.class);
+            basicConverter.convertValue(new HashMap<>(), null, null, null, 1, String.class);
             fail(MSG_EXCEPTION_EXPECTED);
         }catch(Exception ex){
             assertEquals(TypeConversionException.class, ex.getClass());
diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java
index 3465737..9ca0e0e 100644
--- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java
@@ -28,6 +28,8 @@ import com.opensymphony.xwork2.util.Foo;
 import com.opensymphony.xwork2.util.FurColor;
 import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
 import ognl.OgnlRuntime;
+import ognl.TypeConverter;
+import org.apache.struts2.components.*;
 
 import java.io.IOException;
 import java.math.BigDecimal;
@@ -41,6 +43,8 @@ import java.util.*;
 
 import static org.junit.Assert.assertArrayEquals;
 
+import java.util.Date;
+import java.util.Set;
 
 /**
  * @author $Author$
@@ -122,6 +126,29 @@ public class XWorkConverterTest extends XWorkTestCase {
         assertEquals(date, dateRfc3339DateOnly);
     }
 
+    public void testDateConversionWithDefault() throws ParseException {
+        Map<String, String> lookupMap = new HashMap<>();
+        TextProvider tp = new StubTextProvider(lookupMap);
+        StubValueStack valueStack = new StubValueStack();
+        valueStack.push(tp);
+        context.put(ActionContext.VALUE_STACK, valueStack);
+
+        String dateToFormat = "2017---06--15";
+        Object unparseableDate = converter.convertValue(context, null, null, null, dateToFormat, Date.class);
+        assertEquals(unparseableDate, com.opensymphony.xwork2.conversion.TypeConverter.NO_CONVERSION_POSSIBLE);
+
+        lookupMap.put(org.apache.struts2.components.Date.DATETAG_PROPERTY, "yyyy---MM--dd");
+
+        SimpleDateFormat format = new SimpleDateFormat("yyyy---MM--dd");
+        Date expectedDate = format.parse(dateToFormat);
+        Object parseableDate = converter.convertValue(context, null, null, null, dateToFormat, Date.class);
+        assertEquals(expectedDate, parseableDate);
+
+        Object standardDate = converter.convertValue(context, null, null, null, "2017-06-15", Date.class);
+        assertEquals(expectedDate, standardDate);
+
+    }
+
     public void testFieldErrorMessageAddedForComplexProperty() {
         SimpleAction action = new SimpleAction();
         action.setBean(new TestBean());
diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
index 7641dcc..44a8e6e 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
@@ -19,6 +19,8 @@
 package com.opensymphony.xwork2.ognl;
 
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.StubTextProvider;
+import com.opensymphony.xwork2.StubValueStack;
 import com.opensymphony.xwork2.XWorkTestCase;
 import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
@@ -64,13 +66,7 @@ public class OgnlUtilTest extends XWorkTestCase {
 
     // Fields for static field access test
     public static final String STATIC_FINAL_PUBLIC_ATTRIBUTE = "Static_Final_Public_Attribute";
-    static final String STATIC_FINAL_PACKAGE_ATTRIBUTE = "Static_Final_Package_Attribute";
-    protected static final String STATIC_FINAL_PROTECTED_ATTRIBUTE = "Static_Final_Protected_Attribute";
-    private static final String STATIC_FINAL_PRIVATE_ATTRIBUTE = "Static_Final_Private_Attribute";
     public static String STATIC_PUBLIC_ATTRIBUTE = "Static_Public_Attribute";
-    static String STATIC_PACKAGE_ATTRIBUTE = "Static_Package_Attribute";
-    protected static String STATIC_PROTECTED_ATTRIBUTE = "Static_Protected_Attribute";
-    private static String STATIC_PRIVATE_ATTRIBUTE = "Static_Private_Attribute";
 
     private OgnlUtil ognlUtil;
 
@@ -97,9 +93,7 @@ public class OgnlUtilTest extends XWorkTestCase {
                 for (Method method : methods) {
                     String name = method.getName();
 
-                    if (!getter.equals(name) || (method.getParameterTypes().length != 1)) {
-                        continue;
-                    } else {
+                    if (getter.equals(name) && (method.getParameterTypes().length == 1)) {
                         Class<?> clazz = method.getParameterTypes()[0];
 
                         try {
@@ -477,10 +471,17 @@ public class OgnlUtilTest extends XWorkTestCase {
 
         Map<String, Object> context = ognlUtil.createDefaultContext(foo);
 
+        ValueStack stack = new StubValueStack();
+        stack.push(new StubTextProvider(new HashMap<>()));
+
         Map<String, Object> props = new HashMap<>();
         props.put("birthday", "02/12/1982");
         // US style test
-        context = ActionContext.of(context).withLocale(Locale.US).getContextMap();
+        context = ActionContext.of(context)
+            .withLocale(Locale.US)
+            .withValueStack(stack)
+            .getContextMap();
+
         ognlUtil.setProperties(props, foo, context);
 
         Calendar cal = Calendar.getInstance(Locale.US);
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/SimpleActionValidationTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/SimpleActionValidationTest.java
index 503d230..b2e1f2a 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/SimpleActionValidationTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/SimpleActionValidationTest.java
@@ -21,6 +21,8 @@ package com.opensymphony.xwork2.validator;
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ActionProxy;
 import com.opensymphony.xwork2.SimpleAction;
+import com.opensymphony.xwork2.StubTextProvider;
+import com.opensymphony.xwork2.StubValueStack;
 import com.opensymphony.xwork2.TextProviderFactory;
 import com.opensymphony.xwork2.XWorkTestCase;
 import com.opensymphony.xwork2.config.providers.MockConfigurationProvider;
@@ -44,7 +46,7 @@ import java.util.Map;
 public class SimpleActionValidationTest extends XWorkTestCase {
 
     public void testAliasValidation() {
-        HashMap<String, Object> params = new HashMap<>();
+        Map<String, Object> params = new HashMap<>();
         params.put("baz", "10");
 
         //valid values
@@ -52,8 +54,10 @@ public class SimpleActionValidationTest extends XWorkTestCase {
         params.put("date", "12/23/2002");
         params.put("percentage", "1.23456789");
 
-        HashMap<String, Object> extraContext = new HashMap<>();
-        extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
+        Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
+            .withParameters(HttpParameters.create(params).build())
+            .bind()
+            .getContextMap();
 
         try {
             ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.VALIDATION_ACTION_NAME, null, extraContext);
@@ -62,11 +66,11 @@ public class SimpleActionValidationTest extends XWorkTestCase {
             ValidationAware validationAware = (ValidationAware) proxy.getAction();
             assertFalse(validationAware.hasFieldErrors());
 
-            // put in an out-of-range value to see if the old validators still work
-            ActionContext.of(new HashMap<>()).bind();
-
             params.put("bar", "42");
-            extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
+            extraContext = ActionContext.of(new HashMap<>())
+                .withParameters(HttpParameters.create(params).build())
+                .bind()
+                .getContextMap();
 
             proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.VALIDATION_ALIAS_NAME, null, extraContext);
             proxy.execute();