Skip to content

Commit cb7434a

Browse files
committed
Allow multiple date formats for date fields
1 parent 120eed0 commit cb7434a

File tree

6 files changed

+75
-43
lines changed

6 files changed

+75
-43
lines changed

Diff for: src/main/java/org/springframework/data/elasticsearch/annotations/DateFormat.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
* @author Jakub Vavrik
2424
* @author Tim te Beek
2525
* @author Peter-Josef Meisch
26+
* @author Sascha Woo
2627
*/
2728
public enum DateFormat {
28-
none(""), //
2929
custom(""), //
3030
basic_date("uuuuMMdd"), //
3131
basic_date_time("uuuuMMdd'T'HHmmss.SSSXXX"), //

Diff for: src/main/java/org/springframework/data/elasticsearch/annotations/Field.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* @author Aleksei Arsenev
3737
* @author Brian Kimmig
3838
* @author Morgan Lutz
39+
* @author Sascha Woo
3940
*/
4041
@Retention(RetentionPolicy.RUNTIME)
4142
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@@ -65,7 +66,7 @@
6566

6667
boolean index() default true;
6768

68-
DateFormat format() default DateFormat.none;
69+
DateFormat[] format() default { DateFormat.date_optional_time, DateFormat.epoch_millis };
6970

7071
String pattern() default "";
7172

Diff for: src/main/java/org/springframework/data/elasticsearch/annotations/InnerField.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
boolean index() default true;
4242

43-
DateFormat format() default DateFormat.none;
43+
DateFormat[] format() default { DateFormat.date_optional_time, DateFormat.epoch_millis };
4444

4545
String pattern() default "";
4646

Diff for: src/main/java/org/springframework/data/elasticsearch/core/index/MappingParameters.java

+15-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import java.io.IOException;
1919
import java.lang.annotation.Annotation;
20+
import java.util.ArrayList;
21+
import java.util.List;
2022

2123
import org.elasticsearch.common.Nullable;
2224
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -41,6 +43,7 @@
4143
* @author Aleksei Arsenev
4244
* @author Brian Kimmig
4345
* @author Morgan Lutz
46+
* @author Sascha Woo
4447
* @since 4.0
4548
*/
4649
public final class MappingParameters {
@@ -83,7 +86,7 @@ public final class MappingParameters {
8386
private final boolean eagerGlobalOrdinals;
8487
private final boolean enabled;
8588
private final boolean fielddata;
86-
private final DateFormat format;
89+
private final DateFormat[] format;
8790
@Nullable private final Integer ignoreAbove;
8891
private final boolean ignoreMalformed;
8992
private final boolean index;
@@ -226,8 +229,17 @@ public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException
226229

227230
if (type != FieldType.Auto) {
228231
builder.field(FIELD_PARAM_TYPE, type.name().toLowerCase());
229-
if (type == FieldType.Date && format != DateFormat.none) {
230-
builder.field(FIELD_PARAM_FORMAT, format == DateFormat.custom ? datePattern : format.toString());
232+
if (type == FieldType.Date && format.length > 0) {
233+
List<String> formats = new ArrayList<>();
234+
for (int i = 0; i < format.length; i++) {
235+
DateFormat dateFormat = format[i];
236+
if (dateFormat == DateFormat.custom) {
237+
formats.add(datePattern);
238+
} else {
239+
formats.add(format.toString());
240+
}
241+
}
242+
builder.field(FIELD_PARAM_FORMAT, String.join("||", formats));
231243
}
232244
}
233245

Diff for: src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java

+55-36
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.elasticsearch.core.mapping;
1717

1818
import java.time.temporal.TemporalAccessor;
19+
import java.util.ArrayList;
1920
import java.util.Arrays;
2021
import java.util.Date;
2122
import java.util.List;
@@ -154,51 +155,79 @@ private void initDateConverter() {
154155

155156
if (field != null && (field.type() == FieldType.Date || field.type() == FieldType.Date_Nanos)
156157
&& (isTemporalAccessor || isDate)) {
157-
DateFormat dateFormat = field.format();
158+
DateFormat[] dateFormats = field.format();
158159

159160
String property = getOwner().getType().getSimpleName() + "." + getName();
160161

161-
if (dateFormat == DateFormat.none) {
162+
if (dateFormats.length == 0) {
162163
LOGGER.warn(
163164
String.format("No DateFormat defined for property %s. Make sure you have a Converter registered for %s",
164165
property, actualType.getSimpleName()));
165166
return;
166167
}
167168

168-
ElasticsearchDateConverter converter = null;
169+
List<ElasticsearchDateConverter> converters = new ArrayList<>();
169170

170-
if (dateFormat == DateFormat.custom) {
171-
String pattern = field.pattern();
171+
for (int i = 0; i < dateFormats.length; i++) {
172+
DateFormat dateFormat = dateFormats[i];
172173

173-
if (!StringUtils.hasLength(pattern)) {
174-
throw new MappingException(
175-
String.format("Property %s is annotated with FieldType.%s and a custom format but has no pattern defined",
176-
property, field.type().name()));
177-
}
174+
if (dateFormat == DateFormat.custom) {
175+
String pattern = field.pattern();
176+
177+
if (!StringUtils.hasLength(pattern)) {
178+
throw new MappingException(String.format(
179+
"Property %s is annotated with FieldType.%s and a custom format but has no pattern defined", property,
180+
field.type().name()));
181+
}
178182

179-
converter = ElasticsearchDateConverter.of(pattern);
180-
} else {
181-
182-
switch (dateFormat) {
183-
case weekyear:
184-
case weekyear_week:
185-
case weekyear_week_day:
186-
LOGGER.warn("no Converter available for " + actualType.getName() + " and date format " + dateFormat.name()
187-
+ ". Use a custom converter instead");
188-
break;
189-
default:
190-
converter = ElasticsearchDateConverter.of(dateFormat);
191-
break;
183+
converters.add(ElasticsearchDateConverter.of(pattern));
184+
} else {
185+
186+
switch (dateFormat) {
187+
case weekyear:
188+
case weekyear_week:
189+
case weekyear_week_day:
190+
LOGGER.warn("no Converter available for " + actualType.getName() + " and date format " + dateFormat.name()
191+
+ ". Use a custom converter instead");
192+
break;
193+
default:
194+
converters.add(ElasticsearchDateConverter.of(dateFormat));
195+
break;
196+
}
192197
}
198+
193199
}
194200

195-
if (converter != null) {
196-
ElasticsearchDateConverter finalConverter = converter;
201+
if (!converters.isEmpty()) {
197202
propertyConverter = new ElasticsearchPersistentPropertyConverter() {
198-
final ElasticsearchDateConverter dateConverter = finalConverter;
203+
final List<ElasticsearchDateConverter> dateConverters = converters;
204+
205+
@SuppressWarnings("unchecked")
206+
@Override
207+
public Object read(String s) {
208+
if (isTemporalAccessor) {
209+
for (ElasticsearchDateConverter dateConverter : dateConverters) {
210+
try {
211+
return dateConverter.parse(s, (Class<? extends TemporalAccessor>) actualType);
212+
} catch (Exception e) {
213+
}
214+
}
215+
} else { // must be date
216+
for (ElasticsearchDateConverter dateConverter : dateConverters) {
217+
try {
218+
return dateConverter.parse(s);
219+
} catch (Exception e) {
220+
}
221+
}
222+
}
223+
224+
throw new RuntimeException(String
225+
.format("Unable to parse date value '%s' of property '%s' with configured converters", s, property));
226+
}
199227

200228
@Override
201229
public String write(Object property) {
230+
ElasticsearchDateConverter dateConverter = dateConverters.get(0);
202231
if (isTemporalAccessor && TemporalAccessor.class.isAssignableFrom(property.getClass())) {
203232
return dateConverter.format((TemporalAccessor) property);
204233
} else if (isDate && Date.class.isAssignableFrom(property.getClass())) {
@@ -207,16 +236,6 @@ public String write(Object property) {
207236
return property.toString();
208237
}
209238
}
210-
211-
@SuppressWarnings("unchecked")
212-
@Override
213-
public Object read(String s) {
214-
if (isTemporalAccessor) {
215-
return dateConverter.parse(s, (Class<? extends TemporalAccessor>) actualType);
216-
} else { // must be date
217-
return dateConverter.parse(s);
218-
}
219-
}
220239
};
221240
}
222241
}

Diff for: src/test/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchDateConverterUnitTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
/**
2424
* @author Peter-Josef Meisch
2525
* @author Tim te Beek
26+
* @author Sascha Woo
2627
*/
2728
class ElasticsearchDateConverterUnitTests {
2829

@@ -33,7 +34,6 @@ class ElasticsearchDateConverterUnitTests {
3334
void shouldCreateConvertersForAllKnownFormats(DateFormat dateFormat) {
3435

3536
switch (dateFormat) {
36-
case none:
3737
case weekyear:
3838
case weekyear_week:
3939
case weekyear_week_day:

0 commit comments

Comments
 (0)