From 9e65c4c85354af6f8532f8694e91b50133e44b0f Mon Sep 17 00:00:00 2001 From: "Cabasson, Denis - CoSD/DSCo" Date: Mon, 12 Jun 2017 16:26:02 -0400 Subject: [PATCH] WW-4799 Adding struts.date.format as a conversion format for DateConverter --- .../xwork2/conversion/impl/DateConverter.java | 53 +++++++++++- .../opensymphony/xwork2/StubTextProvider.java | 80 +++++++++++++++++++ .../conversion/impl/XWorkConverterTest.java | 28 ++++++- 3 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 core/src/test/java/com/opensymphony/xwork2/StubTextProvider.java 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 bde36f7733..d2fcc7f10e 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 @@ -1,6 +1,9 @@ package com.opensymphony.xwork2.conversion.impl; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.TextProvider; import com.opensymphony.xwork2.XWorkException; +import com.opensymphony.xwork2.util.ValueStack; import java.lang.reflect.Constructor; import java.lang.reflect.Member; @@ -48,7 +51,28 @@ public Object convertValue(Map context, Object target, Member me } } else if (java.util.Date.class == toType) { Date check; - DateFormat[] dfs = getDateFormats(locale); + + + // Add the user provided date format if any + final TextProvider tp = findProviderInStack((ValueStack) context.get(ActionContext.VALUE_STACK)); + SimpleDateFormat globalDateFormat = null; + + 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); + } + } + + DateFormat[] dfs = getDateFormats(globalDateFormat, locale); + + + for (DateFormat df1 : dfs) { try { check = df1.parse(sa); @@ -84,7 +108,13 @@ public Object convertValue(Map context, Object target, Member me return result; } - private DateFormat[] getDateFormats(Locale locale) { + /** + * Retrieves the list of date formats to be used when converting dates + * @param df the user defined, global date format (see {@link org.apache.struts2.components.Date#DATETAG_PROPERTY} + * @param locale the current locale of the action + * @return a list of DateFormat to be used for date conversion + */ + private DateFormat[] getDateFormats(DateFormat df, Locale 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); @@ -96,7 +126,24 @@ private DateFormat[] getDateFormats(Locale locale) { 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 (df == null) { + dateFormats = new DateFormat[]{dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly}; + } else { + dateFormats = new DateFormat[]{df, 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 0000000000..4908cb5269 --- /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 map; + + public StubTextProvider(final Map 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 4607805231..36cac12556 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 @@ -26,6 +26,8 @@ import com.opensymphony.xwork2.util.reflection.ReflectionContextState; import ognl.OgnlException; import ognl.OgnlRuntime; +import ognl.TypeConverter; +import org.apache.struts2.components.*; import java.io.IOException; import java.math.BigDecimal; @@ -36,7 +38,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; - +import java.util.Date; +import java.util.Set; /** * @author $Author$ @@ -118,6 +121,29 @@ public void testDateConversion() throws ParseException { assertEquals(date, dateRfc3339DateOnly); } + public void testDateConversionWithDefault() throws ParseException { + Map 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());