mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-07-31 06:33:26 +00:00
DATAES-792 - Add java.util.Date to the supported types for Field annotation date times.
Original PR: #432
This commit is contained in:
parent
f6a37f4601
commit
e49f140233
@ -17,7 +17,9 @@ package org.springframework.data.elasticsearch.core.convert;
|
|||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.elasticsearch.common.time.DateFormatter;
|
import org.elasticsearch.common.time.DateFormatter;
|
||||||
@ -73,9 +75,25 @@ final public class ElasticsearchDateConverter {
|
|||||||
* @return the formatted object
|
* @return the formatted object
|
||||||
*/
|
*/
|
||||||
public String format(TemporalAccessor accessor) {
|
public String format(TemporalAccessor accessor) {
|
||||||
|
|
||||||
|
Assert.notNull(accessor, "accessor must not be null");
|
||||||
|
|
||||||
return dateFormatter.format(accessor);
|
return dateFormatter.format(accessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the given {@link TemporalAccessor} int a String
|
||||||
|
*
|
||||||
|
* @param date must not be {@literal null}
|
||||||
|
* @return the formatted object
|
||||||
|
*/
|
||||||
|
public String format(Date date) {
|
||||||
|
|
||||||
|
Assert.notNull(date, "accessor must not be null");
|
||||||
|
|
||||||
|
return dateFormatter.format(Instant.ofEpochMilli(date.getTime()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a String into an object
|
* Parses a String into an object
|
||||||
*
|
*
|
||||||
@ -96,4 +114,14 @@ final public class ElasticsearchDateConverter {
|
|||||||
throw new ConversionException("could not create object of class " + type.getName(), e);
|
throw new ConversionException("could not create object of class " + type.getName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a String into a Date.
|
||||||
|
*
|
||||||
|
* @param input the String to parse, must not be {@literal null}.
|
||||||
|
* @return the new created object
|
||||||
|
*/
|
||||||
|
public Date parse(String input) {
|
||||||
|
return new Date(Instant.from(dateFormatter.parse(input)).toEpochMilli());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core.mapping;
|
|||||||
|
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||||
@ -95,11 +96,14 @@ public class SimpleElasticsearchPersistentProperty extends
|
|||||||
/**
|
/**
|
||||||
* Initializes an {@link ElasticsearchPersistentPropertyConverter} if this property is annotated as a Field with type
|
* Initializes an {@link ElasticsearchPersistentPropertyConverter} if this property is annotated as a Field with type
|
||||||
* {@link FieldType#Date}, has a {@link DateFormat} set and if the type of the property is one of the Java8 temporal
|
* {@link FieldType#Date}, has a {@link DateFormat} set and if the type of the property is one of the Java8 temporal
|
||||||
* classes.
|
* classes or java.util.Date.
|
||||||
*/
|
*/
|
||||||
private void initDateConverter() {
|
private void initDateConverter() {
|
||||||
Field field = findAnnotation(Field.class);
|
Field field = findAnnotation(Field.class);
|
||||||
if (field != null && field.type() == FieldType.Date && TemporalAccessor.class.isAssignableFrom(getType())) {
|
boolean isTemporalAccessor = TemporalAccessor.class.isAssignableFrom(getType());
|
||||||
|
boolean isDate = Date.class.isAssignableFrom(getType());
|
||||||
|
|
||||||
|
if (field != null && field.type() == FieldType.Date && (isTemporalAccessor || isDate)) {
|
||||||
DateFormat dateFormat = field.format();
|
DateFormat dateFormat = field.format();
|
||||||
|
|
||||||
ElasticsearchDateConverter converter = null;
|
ElasticsearchDateConverter converter = null;
|
||||||
@ -119,13 +123,21 @@ public class SimpleElasticsearchPersistentProperty extends
|
|||||||
propertyConverter = new ElasticsearchPersistentPropertyConverter() {
|
propertyConverter = new ElasticsearchPersistentPropertyConverter() {
|
||||||
@Override
|
@Override
|
||||||
public String write(Object property) {
|
public String write(Object property) {
|
||||||
return dateConverter.format((TemporalAccessor) property);
|
if (isTemporalAccessor) {
|
||||||
|
return dateConverter.format((TemporalAccessor) property);
|
||||||
|
} else { // must be Date
|
||||||
|
return dateConverter.format((Date) property);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object read(String s) {
|
public Object read(String s) {
|
||||||
return dateConverter.parse(s, (Class<? extends TemporalAccessor>) getType());
|
if (isTemporalAccessor) {
|
||||||
|
return dateConverter.parse(s, (Class<? extends TemporalAccessor>) getType());
|
||||||
|
} else { // must be date
|
||||||
|
return dateConverter.parse(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package org.springframework.data.elasticsearch.core.convert;
|
|||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
@ -14,7 +16,7 @@ import org.springframework.data.elasticsearch.annotations.DateFormat;
|
|||||||
*/
|
*/
|
||||||
class ElasticsearchDateConverterTests {
|
class ElasticsearchDateConverterTests {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest // DATAES-716
|
||||||
@EnumSource(DateFormat.class)
|
@EnumSource(DateFormat.class)
|
||||||
void shouldCreateConvertersForAllKnownFormats(DateFormat dateFormat) {
|
void shouldCreateConvertersForAllKnownFormats(DateFormat dateFormat) {
|
||||||
|
|
||||||
@ -28,8 +30,8 @@ class ElasticsearchDateConverterTests {
|
|||||||
assertThat(converter).isNotNull();
|
assertThat(converter).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // DATAES-716
|
||||||
void shouldConvertToString() {
|
void shouldConvertTemporalAccessorToString() {
|
||||||
LocalDate localDate = LocalDate.of(2019, 12, 27);
|
LocalDate localDate = LocalDate.of(2019, 12, 27);
|
||||||
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date);
|
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date);
|
||||||
|
|
||||||
@ -38,8 +40,8 @@ class ElasticsearchDateConverterTests {
|
|||||||
assertThat(formatted).isEqualTo("20191227");
|
assertThat(formatted).isEqualTo("20191227");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // DATAES-716
|
||||||
void shouldParseFromString() {
|
void shouldParseTemporalAccessorFromString() {
|
||||||
LocalDate localDate = LocalDate.of(2019, 12, 27);
|
LocalDate localDate = LocalDate.of(2019, 12, 27);
|
||||||
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date);
|
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date);
|
||||||
|
|
||||||
@ -47,4 +49,24 @@ class ElasticsearchDateConverterTests {
|
|||||||
|
|
||||||
assertThat(parsed).isEqualTo(localDate);
|
assertThat(parsed).isEqualTo(localDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAES-792
|
||||||
|
void shouldConvertLegacyDateToString() {
|
||||||
|
Date date = new GregorianCalendar(2020, 3, 19, 21, 44).getTime();
|
||||||
|
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date_time);
|
||||||
|
|
||||||
|
String formatted = converter.format(date);
|
||||||
|
|
||||||
|
assertThat(formatted).isEqualTo("20200419T194400.000Z");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATAES-792
|
||||||
|
void shouldParseLegacyDateFromString() {
|
||||||
|
Date date = new GregorianCalendar(2020, 3, 19, 21, 44).getTime();
|
||||||
|
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date_time);
|
||||||
|
|
||||||
|
Date parsed = converter.parse("20200419T194400.000Z");
|
||||||
|
|
||||||
|
assertThat(parsed).isEqualTo(date);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.*;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||||
@ -69,25 +70,25 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
|
|||||||
assertThat(persistentProperty.getFieldName()).isEqualTo("by-value");
|
assertThat(persistentProperty.getFieldName()).isEqualTo("by-value");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // DATAES-716, DATAES-792
|
||||||
// DATAES-716
|
|
||||||
void shouldSetPropertyConverters() {
|
void shouldSetPropertyConverters() {
|
||||||
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
||||||
|
|
||||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("date");
|
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
|
||||||
assertThat(persistentProperty.hasPropertyConverter()).isFalse();
|
|
||||||
|
|
||||||
persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
|
|
||||||
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
|
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
|
||||||
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
|
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
|
||||||
|
|
||||||
persistentProperty = persistentEntity.getRequiredPersistentProperty("localDateTime");
|
persistentProperty = persistentEntity.getRequiredPersistentProperty("localDateTime");
|
||||||
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
|
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
|
||||||
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
|
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
|
||||||
|
|
||||||
|
persistentProperty = persistentEntity.getRequiredPersistentProperty("legacyDate");
|
||||||
|
assertThat(persistentProperty.hasPropertyConverter()).isTrue();
|
||||||
|
assertThat(persistentProperty.getPropertyConverter()).isNotNull();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // DATAES-716
|
||||||
// DATAES-716
|
|
||||||
void shouldConvertFromLocalDate() {
|
void shouldConvertFromLocalDate() {
|
||||||
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
||||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
|
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
|
||||||
@ -98,8 +99,7 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
|
|||||||
assertThat(converted).isEqualTo("27.12.2019");
|
assertThat(converted).isEqualTo("27.12.2019");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // DATAES-716
|
||||||
// DATAES-716
|
|
||||||
void shouldConvertToLocalDate() {
|
void shouldConvertToLocalDate() {
|
||||||
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
||||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
|
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("localDate");
|
||||||
@ -110,6 +110,28 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
|
|||||||
assertThat(converted).isEqualTo(LocalDate.of(2019, 12, 27));
|
assertThat(converted).isEqualTo(LocalDate.of(2019, 12, 27));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAES_792
|
||||||
|
void shouldConvertFromLegacyDate() {
|
||||||
|
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
||||||
|
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("legacyDate");
|
||||||
|
Date legacyDate = new GregorianCalendar(2020, 3, 19, 21, 44).getTime();
|
||||||
|
|
||||||
|
String converted = persistentProperty.getPropertyConverter().write(legacyDate);
|
||||||
|
|
||||||
|
assertThat(converted).isEqualTo("20200419T194400.000Z");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATES-792
|
||||||
|
void shouldConvertToLegacyDate() {
|
||||||
|
SimpleElasticsearchPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DatesProperty.class);
|
||||||
|
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("legacyDate");
|
||||||
|
|
||||||
|
Object converted = persistentProperty.getPropertyConverter().read("20200419T194400.000Z");
|
||||||
|
|
||||||
|
assertThat(converted).isInstanceOf(Date.class);
|
||||||
|
assertThat(converted).isEqualTo(new GregorianCalendar(2020, 3, 19, 21, 44).getTime());
|
||||||
|
}
|
||||||
|
|
||||||
static class InvalidScoreProperty {
|
static class InvalidScoreProperty {
|
||||||
@Nullable @Score String scoreProperty;
|
@Nullable @Score String scoreProperty;
|
||||||
}
|
}
|
||||||
@ -123,8 +145,8 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class DatesProperty {
|
static class DatesProperty {
|
||||||
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date) Date date;
|
|
||||||
@Nullable @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd.MM.uuuu") LocalDate localDate;
|
@Nullable @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "dd.MM.uuuu") LocalDate localDate;
|
||||||
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
|
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
|
||||||
|
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user