SEARCH-1286 date type casting errors (#27)

* [ SEARCH-1286 ] additional ThreadLocal + date format (UTC - msecs)

* [ SEARCH-1286 ] ThreadLocal + other minor refactoring + unit tests

* [ SEARCH-1286 ] Fixed Timezone issue in Unit tests

* [ SEARCH-1286 ] Fixed Timezone issue II in Unit tests

* [ SEARCH-1286 ] Fixed Locale issue in CachingDataFormat

* Merge branches 'fix/SEARCH-1286_date_type_casting_errors' and 'master' of https://github.com/Alfresco/alfresco-core into fix/SEARCH-1286_date_type_casting_errors

# Conflicts:
#	src/main/java/org/alfresco/util/CachingDateFormat.java
#	src/test/java/org/alfresco/util/CachingDateFormatTest.java
This commit is contained in:
Andrea Gazzarini
2018-11-30 12:06:37 +01:00
committed by GitHub
parent 7ab552310a
commit 51077e8ad0
2 changed files with 48 additions and 27 deletions

View File

@@ -18,7 +18,8 @@
*/ */
package org.alfresco.util; package org.alfresco.util;
import java.text.NumberFormat; import static java.util.Arrays.stream;
import java.text.ParseException; import java.text.ParseException;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -27,8 +28,6 @@ import java.util.*;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat; import org.joda.time.format.ISODateTimeFormat;
import static java.util.Arrays.stream;
/** /**
* Provides <b>thread safe</b> means of obtaining a cached date formatter. * Provides <b>thread safe</b> means of obtaining a cached date formatter.
* <p> * <p>
@@ -85,37 +84,34 @@ public class CachingDateFormat extends SimpleDateFormat
new StringAndResolution("yyyy", Calendar.YEAR) new StringAndResolution("yyyy", Calendar.YEAR)
}; };
private static ThreadLocal<SimpleDateFormat> S_LOCAL_DATE_FORMAT = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_FULL_GENERIC)); static ThreadLocal<SimpleDateFormat> S_LOCAL_DATE_FORMAT = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_FULL_GENERIC));
private static ThreadLocal<SimpleDateFormat> S_LOCAL_DATEONLY_FORMAT = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_DATE_GENERIC)); static ThreadLocal<SimpleDateFormat> S_LOCAL_DATEONLY_FORMAT = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_DATE_GENERIC));
private static ThreadLocal<SimpleDateFormat> S_LOCAL_TIMEONLY_FORMAT = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_TIME_GENERIC)); static ThreadLocal<SimpleDateFormat> S_LOCAL_TIMEONLY_FORMAT = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_TIME_GENERIC));
private static ThreadLocal<SimpleDateFormat> S_LOCAL_CMIS_SQL_DATETIME = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_CMIS_SQL)); static ThreadLocal<SimpleDateFormat> S_LOCAL_CMIS_SQL_DATETIME = ThreadLocal.withInitial(() -> newDateFormat(FORMAT_CMIS_SQL));
private static ThreadLocal<SimpleDateFormat> S_LOCAL_SOLR_DATETIME = ThreadLocal.withInitial(()-> static ThreadLocal<SimpleDateFormat> S_LOCAL_SOLR_DATETIME = ThreadLocal.withInitial(()->
{ {
CachingDateFormat formatter = newDateFormat(FORMAT_SOLR); CachingDateFormat formatter = newDateFormatWithLocale(FORMAT_SOLR, Locale.ENGLISH);
/* /*
SEARCH-1263 SEARCH-1263
Apache Solr only supports the ISO 8601 date format: Apache Solr only supports the ISO 8601 date format:
UTC and western locale are mandatory (only Arabic numerals (0123456789) are supported) UTC and western locale are mandatory (only Arabic numerals (0123456789) are supported)
*/ */
formatter.setTimeZone(TimeZone.getTimeZone(UTC)); formatter.setTimeZone(TimeZone.getTimeZone(UTC));
formatter.setNumberFormat(NumberFormat.getNumberInstance(Locale.ENGLISH));
return formatter; return formatter;
}); });
private static ThreadLocal<SimpleDateFormat> S_UTC_DATETIME_WITHOUT_MSECS = ThreadLocal.withInitial(() -> static ThreadLocal<SimpleDateFormat> S_UTC_DATETIME_WITHOUT_MSECS = ThreadLocal.withInitial(() ->
{ {
CachingDateFormat formatter = newDateFormat(UTC_WITHOUT_MSECS); CachingDateFormat formatter = newDateFormatWithLocale(UTC_WITHOUT_MSECS, Locale.ENGLISH);
formatter.setTimeZone(TimeZone.getTimeZone(UTC)); formatter.setTimeZone(TimeZone.getTimeZone(UTC));
formatter.setNumberFormat(NumberFormat.getNumberInstance(Locale.ENGLISH));
return formatter; return formatter;
}); });
private static ThreadLocal<SimpleDateFormatAndResolution[]> S_LENIENT_PARSERS = static ThreadLocal<SimpleDateFormatAndResolution[]> S_LENIENT_PARSERS =
ThreadLocal.withInitial(() -> ThreadLocal.withInitial(() ->
stream(LENIENT_FORMATS) stream(LENIENT_FORMATS)
.map(format -> { .map(format -> {
@@ -126,6 +122,11 @@ public class CachingDateFormat extends SimpleDateFormat
private Map<String, Date> cacheDates = new WeakHashMap<>(89); private Map<String, Date> cacheDates = new WeakHashMap<>(89);
private CachingDateFormat(String pattern, Locale locale)
{
super(pattern, locale);
}
private CachingDateFormat(String pattern) private CachingDateFormat(String pattern)
{ {
super(pattern); super(pattern);
@@ -325,8 +326,6 @@ public class CachingDateFormat extends SimpleDateFormat
} }
throw new ParseException("Unknown date format", 0); throw new ParseException("Unknown date format", 0);
} }
public static SimpleDateFormatAndResolution[] getLenientFormatters() public static SimpleDateFormatAndResolution[] getLenientFormatters()
@@ -403,4 +402,18 @@ public class CachingDateFormat extends SimpleDateFormat
formatter.setLenient(false); formatter.setLenient(false);
return formatter; return formatter;
} }
/**
* Creates a new non-lenient localised {@link CachingDateFormat} instance.
*
* @param pattern the date / datetime pattern.
* @param locale the locale.
* @return new non-lenient {@link CachingDateFormat} instance.
*/
private static CachingDateFormat newDateFormatWithLocale(String pattern, Locale locale)
{
CachingDateFormat formatter = new CachingDateFormat(pattern, locale);
formatter.setLenient(false);
return formatter;
}
} }

View File

@@ -18,7 +18,12 @@
*/ */
package org.alfresco.util; package org.alfresco.util;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import org.junit.After; import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -29,24 +34,26 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
public class CachingDateFormatTest public class CachingDateFormatTest
{ {
private final LocalDateTime REFERENCE_DATE_TIME = LocalDateTime.of(2018, 4, 1, 10, 0); //2018-04-01 at 10:00am private final LocalDateTime REFERENCE_DATE_TIME = LocalDateTime.of(2018, 4, 1, 10, 0); //2018-04-01 at 10:00am
private final Locale defaultLocale = Locale.getDefault(); private final Locale defaultLocale = Locale.getDefault();
@Before
public void setUp()
{
CachingDateFormat.S_LOCAL_SOLR_DATETIME.remove();
}
@Test @Test
public void solrDatetimeFormat_DateNotUTC_shouldReturnISO8601DateString() public void solrDatetimeFormat_shouldFormatTheMinDate()
{ {
Date shanghaiDate = testDate("Asia/Shanghai"); Date shanghaiDate = testDate("Asia/Shanghai");
SimpleDateFormat solrDatetimeFormat = CachingDateFormat.getSolrDatetimeFormat(); SimpleDateFormat solrDatetimeFormat = CachingDateFormat.getSolrDatetimeFormatWithoutMsecs();
String formattedDate = solrDatetimeFormat.format(shanghaiDate); String formattedDate = solrDatetimeFormat.format(shanghaiDate);
assertThat(formattedDate,is("2018-04-01T02:00:00.000Z")); assertThat(formattedDate,is("2018-04-01T02:00:00Z"));
} }
@Test @Test
@@ -54,6 +61,7 @@ public class CachingDateFormatTest
{ {
for(Locale currentLocale:Locale.getAvailableLocales()) for(Locale currentLocale:Locale.getAvailableLocales())
{ {
CachingDateFormat.S_LOCAL_SOLR_DATETIME.remove();
Locale.setDefault(currentLocale); Locale.setDefault(currentLocale);
Date utcDate = testDate("UTC"); Date utcDate = testDate("UTC");