diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/MappingBuilder.java b/src/main/java/org/springframework/data/elasticsearch/core/index/MappingBuilder.java index 9d6e00566..4be431564 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/index/MappingBuilder.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/MappingBuilder.java @@ -215,6 +215,7 @@ public class MappingBuilder { Field fieldAnnotation = property.findAnnotation(Field.class); boolean isCompletionProperty = isCompletionProperty(property); boolean isNestedOrObjectProperty = isNestedOrObjectProperty(property); + DynamicMapping dynamicMapping = property.findAnnotation(DynamicMapping.class); if (!isCompletionProperty && property.isEntity() && hasRelevantAnnotation(property)) { @@ -228,8 +229,8 @@ public class MappingBuilder { ? elasticsearchConverter.getMappingContext().getPersistentEntity(iterator.next()) : null; - mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty, - fieldAnnotation.type(), fieldAnnotation, property.findAnnotation(DynamicMapping.class)); + mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty, fieldAnnotation.type(), + fieldAnnotation, dynamicMapping); return; } } @@ -244,9 +245,9 @@ public class MappingBuilder { if (isRootObject && fieldAnnotation != null && property.isIdProperty()) { applyDefaultIdFieldMapping(builder, property); } else if (multiField != null) { - addMultiFieldMapping(builder, property, multiField, isNestedOrObjectProperty); + addMultiFieldMapping(builder, property, multiField, isNestedOrObjectProperty, dynamicMapping); } else if (fieldAnnotation != null) { - addSingleFieldMapping(builder, property, fieldAnnotation, isNestedOrObjectProperty); + addSingleFieldMapping(builder, property, fieldAnnotation, isNestedOrObjectProperty, dynamicMapping); } } @@ -320,7 +321,7 @@ public class MappingBuilder { * @throws IOException */ private void addSingleFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property, - Field annotation, boolean nestedOrObjectField) throws IOException { + Field annotation, boolean nestedOrObjectField, @Nullable DynamicMapping dynamicMapping) throws IOException { // build the property json, if empty skip it as this is no valid mapping XContentBuilder propertyBuilder = jsonBuilder().startObject(); @@ -332,6 +333,11 @@ public class MappingBuilder { } builder.startObject(property.getFieldName()); + + if (nestedOrObjectField && dynamicMapping != null) { + builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase()); + } + addFieldMappingParameters(builder, annotation, nestedOrObjectField); builder.endObject(); } @@ -342,10 +348,15 @@ public class MappingBuilder { * @throws IOException */ private void addMultiFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property, - MultiField annotation, boolean nestedOrObjectField) throws IOException { + MultiField annotation, boolean nestedOrObjectField, @Nullable DynamicMapping dynamicMapping) throws IOException { // main field builder.startObject(property.getFieldName()); + + if (nestedOrObjectField && dynamicMapping != null) { + builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase()); + } + addFieldMappingParameters(builder, annotation.mainField(), nestedOrObjectField); // inner fields diff --git a/src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderTests.java index 8ab05883d..9e95a3345 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/MappingBuilderTests.java @@ -541,19 +541,28 @@ public class MappingBuilderTests extends MappingContextBaseTests { assertEquals(expected, mapping, true); } - @Test + @Test // DATAES-148, #1767 void shouldWriteDynamicMappingSettings() throws JSONException { String expected = "{\n" + // - " \"dynamic\": \"false\",\n" + // - " \"properties\": {\n" + // - " \"author\": {\n" + // - " \"dynamic\": \"strict\",\n" + // - " \"type\": \"object\",\n" + // - " \"properties\": {}\n" + // + " \"dynamic\": \"false\",\n" + // + " \"properties\": {\n" + // + " \"author\": {\n" + // + " \"type\": \"object\",\n" + // + " \"dynamic\": \"strict\",\n" + // + " \"properties\": {\n" + // " }\n" + // + " },\n" + // + " \"objectMap\": {\n" + // + " \"type\": \"object\",\n" + // + " \"dynamic\": \"false\"\n" + // + " },\n" + // + " \"nestedObjectMap\": {\n" + // + " \"type\": \"nested\",\n" + // + " \"dynamic\": \"false\"\n" + // " }\n" + // - "}\n"; + " }\n" + // + "}"; // String mapping = getMappingBuilder().buildPropertyMapping(ConfigureDynamicMappingEntity.class); @@ -1058,6 +1067,10 @@ public class MappingBuilderTests extends MappingContextBaseTests { static class ConfigureDynamicMappingEntity { @Nullable @DynamicMapping(DynamicMappingValue.Strict) @Field(type = FieldType.Object) private Author author; + @Nullable @DynamicMapping(DynamicMappingValue.False) @Field( + type = FieldType.Object) private Map objectMap; + @Nullable @DynamicMapping(DynamicMappingValue.False) @Field( + type = FieldType.Nested) private List> nestedObjectMap; @Nullable public Author getAuthor() {