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/10 11:19:12 UTC

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

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 d876a2ad930e41dca3a05f8ba252cb16e92aa3d7
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
---
 .../xwork2/conversion/impl/DateConverter.java      | 67 ++++++++++++++++--
 .../com/opensymphony/xwork2/StubTextProvider.java  | 80 ++++++++++++++++++++++
 .../xwork2/conversion/impl/XWorkConverterTest.java | 27 ++++++++
 3 files changed, 169 insertions(+), 5 deletions(-)

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..8337529 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
@@ -19,6 +19,9 @@
 package com.opensymphony.xwork2.conversion.impl;
 
 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;
@@ -35,7 +38,7 @@ public class DateConverter extends DefaultTypeConverter {
     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 +69,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 +91,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 +106,43 @@ 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) {
+        // Add the user provided date format if any
+        SimpleDateFormat globalDateFormat = null;
+
+        final TextProvider tp = findProviderInStack(context.getValueStack());
+
+        if (tp != null) {
+            String globalFormat = tp.getText(org.apache.struts2.components.Date.DATETAG_PROPERTY);
+
+            // if tp.getText can not find the property then the
+            // returned string is the same as input =
+            // DATETAG_PROPERTY
+            if (globalFormat != null
+                && !org.apache.struts2.components.Date.DATETAG_PROPERTY.equals(globalFormat)) {
+                globalDateFormat = new SimpleDateFormat(globalFormat, locale);
+            }
+        }
+        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 +154,24 @@ 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) {
+        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..4908cb5
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/StubTextProvider.java
@@ -0,0 +1,80 @@
+package com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.util.ValueStack;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * Created by cabaden on 12/06/2017.
+ */
+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/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());