Skip to content

Commit aaef626

Browse files
authored
DATAES-828 - Fields of type date need to have a format defined.
Original PR: spring-projects#457
1 parent c7339dc commit aaef626

File tree

6 files changed

+35
-8
lines changed

6 files changed

+35
-8
lines changed

src/main/asciidoc/reference/elasticsearch-object-mapping.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ The following annotations are available:
4343
* `@Field`: Applied at the field level and defines properties of the field, most of the attributes map to the respective https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html[Elasticsearch Mapping] definitions (the following list is not complete, check the annotation Javadoc for a complete reference):
4444
** `name`: The name of the field as it will be represented in the Elasticsearch document, if not set, the Java field name is used.
4545
** `type`: the field type, can be one of _Text, Keyword, Long, Integer, Short, Byte, Double, Float, Half_Float, Scaled_Float, Date, Date_Nanos, Boolean, Binary, Integer_Range, Float_Range, Long_Range, Double_Range, Date_Range, Ip_Range, Object, Nested, Ip, TokenCount, Percolator, Flattened, Search_As_You_Type_. See https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html[Elasticsearch Mapping Types]
46-
** `format` and `pattern` custom definitions for the _Date_ type.
46+
** `format` and `pattern` definitions for the _Date_ type. `format` must be defined for date types.
4747
** `store`: Flag wether the original field value should be store in Elasticsearch, default value is _false_.
4848
** `analyzer`, `searchAnalyzer`, `normalizer` for specifying custom custom analyzers and normalizer.
4949
* `@GeoPoint`: marks a field as _geo_point_ datatype. Can be omitted if the field is an instance of the `GeoPoint` class.

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,15 @@ private void initDateConverter() {
117117
boolean isTemporalAccessor = TemporalAccessor.class.isAssignableFrom(getType());
118118
boolean isDate = Date.class.isAssignableFrom(getType());
119119

120-
if (field != null && field.type() == FieldType.Date && (isTemporalAccessor || isDate)) {
120+
if (field != null && (field.type() == FieldType.Date || field.type() == FieldType.Date_Nanos)
121+
&& (isTemporalAccessor || isDate)) {
121122
DateFormat dateFormat = field.format();
122123

124+
if (dateFormat == DateFormat.none) {
125+
throw new MappingException(String.format("property %s is annotated with FieldType.%s but has no DateFormat defined",
126+
getName(), field.type().name()));
127+
}
128+
123129
ElasticsearchDateConverter converter = null;
124130

125131
if (dateFormat == DateFormat.custom) {

src/test/java/org/springframework/data/elasticsearch/core/LogEntityTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.context.annotation.Import;
3535
import org.springframework.dao.DataAccessException;
3636
import org.springframework.data.annotation.Id;
37+
import org.springframework.data.elasticsearch.annotations.DateFormat;
3738
import org.springframework.data.elasticsearch.annotations.Document;
3839
import org.springframework.data.elasticsearch.annotations.Field;
3940
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
@@ -146,7 +147,7 @@ static class LogEntity {
146147

147148
@Field(type = Ip) private String ip;
148149

149-
@Field(type = Date) private java.util.Date date;
150+
@Field(type = Date, format = DateFormat.date_time) private java.util.Date date;
150151

151152
private LogEntity() {}
152153

src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ static class AbstractInheritedEntity {
859859

860860
@Nullable @Id private String id;
861861

862-
@Nullable @Field(type = FieldType.Date, index = false) private Date createdDate;
862+
@Nullable @Field(type = FieldType.Date, format = DateFormat.date_time, index = false) private Date createdDate;
863863

864864
@Nullable
865865
public String getId() {

src/test/java/org/springframework/data/elasticsearch/core/index/SimpleElasticsearchDateMappingTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ public class SimpleElasticsearchDateMappingTests extends MappingContextBaseTests
4141

4242
private static final String EXPECTED_MAPPING = "{\"properties\":{\"message\":{\"store\":true,"
4343
+ "\"type\":\"text\",\"index\":false,\"analyzer\":\"standard\"},\"customFormatDate\":{\"type\":\"date\",\"format\":\"dd.MM.uuuu hh:mm\"},"
44-
+ "\"defaultFormatDate\":{\"type\":\"date\"},\"basicFormatDate\":{\""
44+
+ "\"basicFormatDate\":{\""
4545
+ "type\":\"date\",\"format\":\"basic_date\"}}}";
4646

47-
@Test // DATAES-568
47+
@Test // DATAES-568, DATAES-828
4848
public void testCorrectDateMappings() {
4949

5050
String mapping = getMappingBuilder().buildPropertyMapping(SampleDateMappingEntity.class);
@@ -67,8 +67,6 @@ static class SampleDateMappingEntity {
6767
@Field(type = Date, format = DateFormat.custom,
6868
pattern = "dd.MM.uuuu hh:mm") private LocalDateTime customFormatDate;
6969

70-
@Field(type = FieldType.Date) private LocalDateTime defaultFormatDate;
71-
7270
@Field(type = FieldType.Date, format = DateFormat.basic_date) private LocalDateTime basicFormatDate;
7371
}
7472
}

src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentPropertyUnitTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ void seqNoPrimaryTermPropertyShouldNotBeReadable() {
173173
assertThat(seqNoProperty.isReadable()).isFalse();
174174
}
175175

176+
@Test // DATAES-828
177+
void shouldRequireFormatForDateField() {
178+
assertThatExceptionOfType(MappingException.class) //
179+
.isThrownBy(() -> context.getRequiredPersistentEntity(DateFieldWithNoFormat.class)) //
180+
.withMessageContaining("date");
181+
}
182+
183+
@Test // DATAES-828
184+
void shouldRequireFormatForDateNanosField() {
185+
assertThatExceptionOfType(MappingException.class) //
186+
.isThrownBy(() -> context.getRequiredPersistentEntity(DateNanosFieldWithNoFormat.class)) //
187+
.withMessageContaining("date");
188+
}
189+
176190
static class InvalidScoreProperty {
177191
@Nullable @Score String scoreProperty;
178192
}
@@ -195,4 +209,12 @@ static class SeqNoPrimaryTermProperty {
195209
SeqNoPrimaryTerm seqNoPrimaryTerm;
196210
String string;
197211
}
212+
213+
static class DateFieldWithNoFormat {
214+
@Field(type = FieldType.Date) LocalDateTime datetime;
215+
}
216+
217+
static class DateNanosFieldWithNoFormat {
218+
@Field(type = FieldType.Date_Nanos) LocalDateTime datetime;
219+
}
198220
}

0 commit comments

Comments
 (0)