Skip to content

Commit 675b779

Browse files
authored
Allow field names with dots.
Original Pull Request #2504 Closes #2502
1 parent d95af9f commit 675b779

File tree

6 files changed

+123
-4
lines changed

6 files changed

+123
-4
lines changed

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,7 @@ public Object get(ElasticsearchPersistentProperty property) {
14191419

14201420
}
14211421

1422-
if (!fieldName.contains(".")) {
1422+
if (property.hasExplicitFieldName() || !fieldName.contains(".")) {
14231423
return target.get(fieldName);
14241424
}
14251425

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

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
3939
*/
4040
String getFieldName();
4141

42+
/**
43+
* @return {@literal true} if the field name comes from an explicit value in the field annotation
44+
* @since 5.1
45+
*/
46+
boolean hasExplicitFieldName();
47+
4248
/**
4349
* Returns whether the current property is a {@link SeqNoPrimaryTerm} property.
4450
*

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ public boolean storeEmptyValue() {
142142
return storeEmptyValue;
143143
}
144144

145-
protected boolean hasExplicitFieldName() {
145+
@Override
146+
public boolean hasExplicitFieldName() {
146147
return StringUtils.hasText(getAnnotatedFieldName());
147148
}
148149

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

+67
Original file line numberDiff line numberDiff line change
@@ -1947,6 +1947,48 @@ void shouldRespectFieldSettingForEmptyProperties() throws JSONException {
19471947
assertEquals(expected, json, true);
19481948
}
19491949

1950+
@Test // #2502
1951+
@DisplayName("should write entity with dotted field name")
1952+
void shouldWriteEntityWithDottedFieldName() throws JSONException {
1953+
1954+
@Language("JSON")
1955+
var expected = """
1956+
{
1957+
"_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$FieldNameDotsEntity",
1958+
"id": "42",
1959+
"dotted.field": "dotted field"
1960+
}
1961+
""";
1962+
var entity = new FieldNameDotsEntity();
1963+
entity.setId("42");
1964+
entity.setDottedField("dotted field");
1965+
1966+
Document document = Document.create();
1967+
mappingElasticsearchConverter.write(entity, document);
1968+
String json = document.toJson();
1969+
1970+
assertEquals(expected, json, true);
1971+
}
1972+
1973+
@Test // #2502
1974+
@DisplayName("should read entity with dotted field name")
1975+
void shouldReadEntityWithDottedFieldName() {
1976+
1977+
@Language("JSON")
1978+
String json = """
1979+
{
1980+
"id": "42",
1981+
"dotted.field": "dotted field"
1982+
}""";
1983+
1984+
Document document = Document.parse(json);
1985+
1986+
FieldNameDotsEntity entity = mappingElasticsearchConverter.read(FieldNameDotsEntity.class, document);
1987+
1988+
assertThat(entity.id).isEqualTo("42");
1989+
assertThat(entity.getDottedField()).isEqualTo("dotted field");
1990+
}
1991+
19501992
// region entities
19511993
public static class Sample {
19521994
@Nullable public @ReadOnlyProperty String readOnly;
@@ -3150,6 +3192,31 @@ public void setMapToNotWriteWhenEmpty(@Nullable Map<String, String> mapToNotWrit
31503192
this.mapToNotWriteWhenEmpty = mapToNotWriteWhenEmpty;
31513193
}
31523194
}
3195+
static class FieldNameDotsEntity {
3196+
@Id
3197+
@Nullable private String id;
3198+
@Nullable
3199+
@Field(name = "dotted.field", type = FieldType.Text) private String dottedField;
3200+
3201+
@Nullable
3202+
public String getId() {
3203+
return id;
3204+
}
3205+
3206+
public void setId(@Nullable String id) {
3207+
this.id = id;
3208+
}
3209+
3210+
@Nullable
3211+
public String getDottedField() {
3212+
return dottedField;
3213+
}
3214+
3215+
public void setDottedField(@Nullable String dottedField) {
3216+
this.dottedField = dottedField;
3217+
}
3218+
}
3219+
31533220
// endregion
31543221

31553222
private static String reverse(Object o) {

Diff for: src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderIntegrationTests.java

+15
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ void shouldWriteSourceExcludes() {
279279
indexOps.createWithMapping();
280280
}
281281

282+
@Test // #2502
283+
@DisplayName(" should write mapping with field name with dots")
284+
void shouldWriteMappingWithFieldNameWithDots() {
285+
286+
IndexOperations indexOps = operations.indexOps(FieldNameDotsEntity.class);
287+
indexOps.createWithMapping();
288+
}
289+
282290
// region Entities
283291
@Document(indexName = "#{@indexNameProvider.indexName()}")
284292
static class Book {
@@ -901,5 +909,12 @@ private static class EntityWithAllTypes {
901909
@Nullable
902910
@Field(type = FieldType.Dense_Vector, dims = 1) String denseVectorField;
903911
}
912+
@Document(indexName = "#{@indexNameProvider.indexName()}")
913+
private static class FieldNameDotsEntity {
914+
@Id
915+
@Nullable private String id;
916+
@Nullable
917+
@Field(name = "dotted.field", type = Text) private String dottedField;
918+
}
904919
// endregion
905920
}

Diff for: src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderUnitTests.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,30 @@ void shouldNotWriteMappingForPropertyWithIndexedIndexNameAnotation() throws JSON
10651065

10661066
assertEquals(expected, mapping, true);
10671067
}
1068+
1069+
@Test // #2502
1070+
@DisplayName("should use custom name with dots")
1071+
void shouldUseCustomNameWithDots() throws JSONException {
1072+
1073+
var expected = """
1074+
{
1075+
"properties": {
1076+
"_class": {
1077+
"type": "keyword",
1078+
"index": false,
1079+
"doc_values": false
1080+
},
1081+
"dotted.field": {
1082+
"type": "text"
1083+
}
1084+
}
1085+
}
1086+
""";
1087+
String mapping = getMappingBuilder().buildPropertyMapping(FieldNameDotsEntity.class);
1088+
1089+
assertEquals(expected, mapping, true);
1090+
}
1091+
10681092
// region entities
10691093

10701094
@Document(indexName = "ignore-above-index")
@@ -2220,8 +2244,14 @@ private static class IndexedIndexNameEntity {
22202244
@Nullable
22212245
@Field(type = Text) private String someText;
22222246
@Nullable
2223-
@IndexedIndexName
2224-
private String storedIndexName;
2247+
@IndexedIndexName private String storedIndexName;
2248+
}
2249+
2250+
private static class FieldNameDotsEntity {
2251+
@Id
2252+
@Nullable private String id;
2253+
@Nullable
2254+
@Field(name = "dotted.field", type = Text) private String dottedField;
22252255
}
22262256
// endregion
22272257
}

0 commit comments

Comments
 (0)