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 <[email protected]> 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());
