diff --git a/pom.xml b/pom.xml
index 71345f9a1..339499606 100644
--- a/pom.xml
+++ b/pom.xml
@@ -227,6 +227,13 @@
+
+ org.skyscreamer
+ jsonassert
+ 1.5.0
+ test
+
+
org.apache.xbean
diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java
index ac798af91..fd511f6d2 100644
--- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java
+++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java
@@ -17,7 +17,6 @@
import static org.elasticsearch.client.Requests.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
-import static org.springframework.data.elasticsearch.core.MappingBuilder.*;
import static org.springframework.util.CollectionUtils.isEmpty;
import static org.springframework.util.StringUtils.*;
@@ -223,18 +222,12 @@ public boolean putMapping(Class clazz) {
logger.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
}
}
- ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
- XContentBuilder xContentBuilder = null;
try {
-
- ElasticsearchPersistentProperty property = persistentEntity.getRequiredIdProperty();
-
- xContentBuilder = buildMapping(clazz, persistentEntity.getIndexType(), property.getFieldName(),
- persistentEntity.getParentType());
+ MappingBuilder mappingBuilder = new MappingBuilder(elasticsearchConverter);
+ return putMapping(clazz, mappingBuilder.buildMapping(clazz));
} catch (Exception e) {
throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);
}
- return putMapping(clazz, xContentBuilder);
}
@Override
diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java
index c543d84bd..245531b6c 100755
--- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java
+++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java
@@ -17,7 +17,6 @@
import static org.elasticsearch.client.Requests.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
-import static org.springframework.data.elasticsearch.core.MappingBuilder.*;
import static org.springframework.util.CollectionUtils.*;
import java.io.BufferedReader;
@@ -205,18 +204,12 @@ public boolean putMapping(Class clazz) {
LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
}
}
- ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
- XContentBuilder xContentBuilder = null;
try {
-
- ElasticsearchPersistentProperty property = persistentEntity.getRequiredIdProperty();
-
- xContentBuilder = buildMapping(clazz, persistentEntity.getIndexType(), property.getFieldName(),
- persistentEntity.getParentType());
+ MappingBuilder mappingBuilder = new MappingBuilder(elasticsearchConverter);
+ return putMapping(clazz, mappingBuilder.buildMapping(clazz));
} catch (Exception e) {
throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);
}
- return putMapping(clazz, xContentBuilder);
}
@Override
diff --git a/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java b/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java
index 2029ff996..94f82957c 100644
--- a/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java
+++ b/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java
@@ -20,31 +20,25 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.util.Iterator;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
-import org.springframework.core.ResolvableType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.annotation.Transient;
-import org.springframework.data.elasticsearch.annotations.CompletionContext;
-import org.springframework.data.elasticsearch.annotations.CompletionField;
-import org.springframework.data.elasticsearch.annotations.DateFormat;
-import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
-import org.springframework.data.elasticsearch.annotations.Field;
-import org.springframework.data.elasticsearch.annotations.FieldType;
-import org.springframework.data.elasticsearch.annotations.GeoPointField;
-import org.springframework.data.elasticsearch.annotations.InnerField;
-import org.springframework.data.elasticsearch.annotations.Mapping;
-import org.springframework.data.elasticsearch.annotations.MultiField;
+import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.core.completion.Completion;
+import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
+import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
+import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
+import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.model.SimpleTypeHolder;
-import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
+import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
@@ -63,6 +57,7 @@
* @author Nordine Bittich
* @author Robert Gruendler
* @author Petr Kukral
+ * @author Peter-Josef Meisch
*/
class MappingBuilder {
@@ -92,169 +87,199 @@ class MappingBuilder {
public static final String TYPE_VALUE_COMPLETION = "completion";
public static final String TYPE_VALUE_GEO_HASH_PREFIX = "geohash_prefix";
public static final String TYPE_VALUE_GEO_HASH_PRECISION = "geohash_precision";
-
+ private static final Logger logger = LoggerFactory.getLogger(ElasticsearchRestTemplate.class);
private static SimpleTypeHolder SIMPLE_TYPE_HOLDER = SimpleTypeHolder.DEFAULT;
+ private final ElasticsearchConverter elasticsearchConverter;
- static XContentBuilder buildMapping(Class> clazz, String indexType, String idFieldName, String parentType) throws IOException {
+ MappingBuilder(ElasticsearchConverter elasticsearchConverter) {
+ this.elasticsearchConverter = elasticsearchConverter;
+ }
- XContentBuilder mapping = jsonBuilder().startObject().startObject(indexType);
+ /**
+ * builds the Elasticsearch mapping for the given clazz.
+ *
+ * @return JSON string
+ * @throws IOException
+ */
+ String buildMapping(Class> clazz) throws IOException {
+
+ ElasticsearchPersistentEntity> entity = elasticsearchConverter.getMappingContext()
+ .getRequiredPersistentEntity(clazz);
+
+ XContentBuilder builder = jsonBuilder().startObject().startObject(entity.getIndexType());
// Dynamic templates
- addDynamicTemplatesMapping(mapping, clazz);
+ addDynamicTemplatesMapping(builder, entity);
// Parent
+ String parentType = entity.getParentType();
if (hasText(parentType)) {
- mapping.startObject(FIELD_PARENT).field(FIELD_TYPE, parentType).endObject();
+ builder.startObject(FIELD_PARENT).field(FIELD_TYPE, parentType).endObject();
}
// Properties
- XContentBuilder xContentBuilder = mapping.startObject(FIELD_PROPERTIES);
+ builder.startObject(FIELD_PROPERTIES);
+
+ mapEntity(builder, entity, true, "", false, FieldType.Auto, null);
- mapEntity(xContentBuilder, clazz, true, idFieldName, "", false, FieldType.Auto, null);
+ builder.endObject() // FIELD_PROPERTIES
+ .endObject() // indexType
+ .endObject() // root object
+ .close();
- return xContentBuilder.endObject().endObject().endObject();
+ return builder.getOutputStream().toString();
}
- private static void mapEntity(XContentBuilder xContentBuilder, Class> clazz, boolean isRootObject, String idFieldName,
- String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType, Field fieldAnnotation) throws IOException {
+ private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersistentEntity entity, boolean isRootObject,
+ String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType,
+ @Nullable Field parentFieldAnnotation) throws IOException {
- java.lang.reflect.Field[] fields = retrieveFields(clazz);
+ boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
+ if (writeNestedProperties) {
- if (!isRootObject && (isAnyPropertyAnnotatedAsField(fields) || nestedOrObjectField)) {
- String type = FieldType.Object.toString().toLowerCase();
- if (nestedOrObjectField) {
- type = fieldType.toString().toLowerCase();
- }
- XContentBuilder t = xContentBuilder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type);
+ String type = nestedOrObjectField ? fieldType.toString().toLowerCase()
+ : FieldType.Object.toString().toLowerCase();
+ builder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type);
+
+ if (nestedOrObjectField && FieldType.Nested == fieldType && parentFieldAnnotation != null
+ && parentFieldAnnotation.includeInParent()) {
- if (nestedOrObjectField && FieldType.Nested == fieldType && fieldAnnotation.includeInParent()) {
- t.field("include_in_parent", fieldAnnotation.includeInParent());
+ builder.field("include_in_parent", parentFieldAnnotation.includeInParent());
}
- t.startObject(FIELD_PROPERTIES);
+
+ builder.startObject(FIELD_PROPERTIES);
}
+ if (entity != null) {
+
+ entity.doWithProperties((PropertyHandler) property -> {
+ try {
+ if (property.isAnnotationPresent(Transient.class) || isInIgnoreFields(property, parentFieldAnnotation)) {
+ return;
+ }
- for (java.lang.reflect.Field field : fields) {
+ if (property.isAnnotationPresent(Mapping.class)) {
- if (field.isAnnotationPresent(Transient.class) || isInIgnoreFields(field, fieldAnnotation)) {
- continue;
- }
+ String mappingPath = property.getRequiredAnnotation(Mapping.class).mappingPath();
+ if (!StringUtils.isEmpty(mappingPath)) {
- if (field.isAnnotationPresent(Mapping.class)) {
- String mappingPath = field.getAnnotation(Mapping.class).mappingPath();
- if (!StringUtils.isEmpty(mappingPath)) {
- ClassPathResource mappings = new ClassPathResource(mappingPath);
- if (mappings.exists()) {
- xContentBuilder.rawField(field.getName(), mappings.getInputStream(), XContentType.JSON);
- continue;
+ ClassPathResource mappings = new ClassPathResource(mappingPath);
+ if (mappings.exists()) {
+ builder.rawField(property.getFieldName(), mappings.getInputStream(), XContentType.JSON);
+ return;
+ }
+ }
}
- }
- }
- boolean isGeoPointField = isGeoPointField(field);
- boolean isCompletionField = isCompletionField(field);
+ boolean isGeoPointProperty = isGeoPointProperty(property);
+ boolean isCompletionProperty = isCompletionProperty(property);
+ boolean isNestedOrObjectProperty = isNestedOrObjectProperty(property);
- Field singleField = field.getAnnotation(Field.class);
- if (!isGeoPointField && !isCompletionField && isEntity(field) && isAnnotated(field)) {
- if (singleField == null) {
- continue;
- }
- boolean nestedOrObject = isNestedOrObjectField(field);
- mapEntity(xContentBuilder, getFieldType(field), false, "", field.getName(), nestedOrObject, singleField.type(), field.getAnnotation(Field.class));
- if (nestedOrObject) {
- continue;
- }
- }
+ Field fieldAnnotation = property.findAnnotation(Field.class);
+ if (!isGeoPointProperty && !isCompletionProperty && property.isEntity() && hasRelevantAnnotation(property)) {
- MultiField multiField = field.getAnnotation(MultiField.class);
+ if (fieldAnnotation == null) {
+ return;
+ }
- if (isGeoPointField) {
- applyGeoPointFieldMapping(xContentBuilder, field);
- }
+ Iterator extends TypeInformation>> iterator = property.getPersistentEntityTypes().iterator();
+ ElasticsearchPersistentEntity> persistentEntity = iterator.hasNext()
+ ? elasticsearchConverter.getMappingContext().getPersistentEntity(iterator.next())
+ : null;
- if (isCompletionField) {
- CompletionField completionField = field.getAnnotation(CompletionField.class);
- applyCompletionFieldMapping(xContentBuilder, field, completionField);
- }
+ mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty,
+ fieldAnnotation.type(), fieldAnnotation);
- if (isRootObject && singleField != null && isIdField(field, idFieldName)) {
- applyDefaultIdFieldMapping(xContentBuilder, field);
- } else if (multiField != null) {
- addMultiFieldMapping(xContentBuilder, field, multiField, isNestedOrObjectField(field));
- } else if (singleField != null) {
- addSingleFieldMapping(xContentBuilder, field, singleField, isNestedOrObjectField(field));
- }
- }
+ if (isNestedOrObjectProperty) {
+ return;
+ }
+ }
- if (!isRootObject && isAnyPropertyAnnotatedAsField(fields) || nestedOrObjectField) {
- xContentBuilder.endObject().endObject();
- }
- }
+ MultiField multiField = property.findAnnotation(MultiField.class);
+
+ if (isGeoPointProperty) {
+ applyGeoPointFieldMapping(builder, property);
+ return;
+ }
- private static java.lang.reflect.Field[] retrieveFields(Class> clazz) {
- // Create list of fields.
- List fields = new ArrayList<>();
+ if (isCompletionProperty) {
+ CompletionField completionField = property.findAnnotation(CompletionField.class);
+ applyCompletionFieldMapping(builder, property, completionField);
+ }
- // Keep backing up the inheritance hierarchy.
- Class> targetClass = clazz;
- do {
- fields.addAll(Arrays.asList(targetClass.getDeclaredFields()));
- targetClass = targetClass.getSuperclass();
+ if (isRootObject && fieldAnnotation != null && property.isIdProperty()) {
+ applyDefaultIdFieldMapping(builder, property);
+ } else if (multiField != null) {
+ addMultiFieldMapping(builder, property, multiField, isNestedOrObjectProperty);
+ } else if (fieldAnnotation != null) {
+ addSingleFieldMapping(builder, property, fieldAnnotation, isNestedOrObjectProperty);
+ }
+ } catch (IOException e) {
+ logger.warn("error mapping property with name {}", property.getName(), e);
+ }
+ });
}
- while (targetClass != null && targetClass != Object.class);
- return fields.toArray(new java.lang.reflect.Field[fields.size()]);
+ if (writeNestedProperties) {
+ builder.endObject().endObject();
+ }
}
- private static boolean isAnnotated(java.lang.reflect.Field field) {
- return field.getAnnotation(Field.class) != null ||
- field.getAnnotation(MultiField.class) != null ||
- field.getAnnotation(GeoPointField.class) != null ||
- field.getAnnotation(CompletionField.class) != null;
+ private boolean hasRelevantAnnotation(ElasticsearchPersistentProperty property) {
+
+ return property.findAnnotation(Field.class) != null || property.findAnnotation(MultiField.class) != null
+ || property.findAnnotation(GeoPointField.class) != null
+ || property.findAnnotation(CompletionField.class) != null;
}
- private static void applyGeoPointFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field) throws IOException {
- xContentBuilder.startObject(field.getName());
- xContentBuilder.field(FIELD_TYPE, TYPE_VALUE_GEO_POINT);
- xContentBuilder.endObject();
+ private void applyGeoPointFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
+ throws IOException {
+
+ builder.startObject(property.getFieldName()).field(FIELD_TYPE, TYPE_VALUE_GEO_POINT).endObject();
}
- private static void applyCompletionFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field, CompletionField annotation) throws IOException {
- xContentBuilder.startObject(field.getName());
- xContentBuilder.field(FIELD_TYPE, TYPE_VALUE_COMPLETION);
+ private void applyCompletionFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
+ @Nullable CompletionField annotation) throws IOException {
+
+ builder.startObject(property.getFieldName());
+ builder.field(FIELD_TYPE, TYPE_VALUE_COMPLETION);
+
if (annotation != null) {
- xContentBuilder.field(COMPLETION_MAX_INPUT_LENGTH, annotation.maxInputLength());
- xContentBuilder.field(COMPLETION_PRESERVE_POSITION_INCREMENTS, annotation.preservePositionIncrements());
- xContentBuilder.field(COMPLETION_PRESERVE_SEPARATORS, annotation.preserveSeparators());
+
+ builder.field(COMPLETION_MAX_INPUT_LENGTH, annotation.maxInputLength());
+ builder.field(COMPLETION_PRESERVE_POSITION_INCREMENTS, annotation.preservePositionIncrements());
+ builder.field(COMPLETION_PRESERVE_SEPARATORS, annotation.preserveSeparators());
if (!StringUtils.isEmpty(annotation.searchAnalyzer())) {
- xContentBuilder.field(FIELD_SEARCH_ANALYZER, annotation.searchAnalyzer());
+ builder.field(FIELD_SEARCH_ANALYZER, annotation.searchAnalyzer());
}
if (!StringUtils.isEmpty(annotation.analyzer())) {
- xContentBuilder.field(FIELD_INDEX_ANALYZER, annotation.analyzer());
+ builder.field(FIELD_INDEX_ANALYZER, annotation.analyzer());
}
+
if (annotation.contexts().length > 0) {
- xContentBuilder.startArray(COMPLETION_CONTEXTS);
+
+ builder.startArray(COMPLETION_CONTEXTS);
for (CompletionContext context : annotation.contexts()) {
- xContentBuilder.startObject();
- xContentBuilder.field(FIELD_CONTEXT_NAME, context.name());
- xContentBuilder.field(FIELD_CONTEXT_TYPE, context.type().name().toLowerCase());
+
+ builder.startObject();
+ builder.field(FIELD_CONTEXT_NAME, context.name());
+ builder.field(FIELD_CONTEXT_TYPE, context.type().name().toLowerCase());
if (context.precision().length() > 0) {
- xContentBuilder.field(FIELD_CONTEXT_PRECISION, context.precision());
+ builder.field(FIELD_CONTEXT_PRECISION, context.precision());
}
- xContentBuilder.endObject();
+ builder.endObject();
}
- xContentBuilder.endArray();
+ builder.endArray();
}
}
- xContentBuilder.endObject();
+ builder.endObject();
}
- private static void applyDefaultIdFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field)
+ private void applyDefaultIdFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
throws IOException {
- xContentBuilder.startObject(field.getName())
- .field(FIELD_TYPE, TYPE_VALUE_KEYWORD)
- .field(FIELD_INDEX, true);
- xContentBuilder.endObject();
+
+ builder.startObject(property.getFieldName()).field(FIELD_TYPE, TYPE_VALUE_KEYWORD).field(FIELD_INDEX, true)
+ .endObject();
}
/**
@@ -262,8 +287,10 @@ private static void applyDefaultIdFieldMapping(XContentBuilder xContentBuilder,
*
* @throws IOException
*/
- private static void addSingleFieldMapping(XContentBuilder builder, java.lang.reflect.Field field, Field annotation, boolean nestedOrObjectField) throws IOException {
- builder.startObject(field.getName());
+ private void addSingleFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
+ Field annotation, boolean nestedOrObjectField) throws IOException {
+
+ builder.startObject(property.getFieldName());
addFieldMappingParameters(builder, annotation, nestedOrObjectField);
builder.endObject();
}
@@ -273,14 +300,11 @@ private static void addSingleFieldMapping(XContentBuilder builder, java.lang.ref
*
* @throws IOException
*/
- private static void addMultiFieldMapping(
- XContentBuilder builder,
- java.lang.reflect.Field field,
- MultiField annotation,
- boolean nestedOrObjectField) throws IOException {
+ private void addMultiFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
+ MultiField annotation, boolean nestedOrObjectField) throws IOException {
// main field
- builder.startObject(field.getName());
+ builder.startObject(property.getFieldName());
addFieldMappingParameters(builder, annotation.mainField(), nestedOrObjectField);
// inner fields
@@ -295,7 +319,8 @@ private static void addMultiFieldMapping(
builder.endObject();
}
- private static void addFieldMappingParameters(XContentBuilder builder, Object annotation, boolean nestedOrObjectField) throws IOException {
+ private void addFieldMappingParameters(XContentBuilder builder, Object annotation, boolean nestedOrObjectField)
+ throws IOException {
boolean index = true;
boolean store = false;
boolean fielddata = false;
@@ -371,15 +396,19 @@ private static void addFieldMappingParameters(XContentBuilder builder, Object an
*
* @throws IOException
*/
- private static void addDynamicTemplatesMapping(XContentBuilder builder, Class> clazz) throws IOException {
- if (clazz.isAnnotationPresent(DynamicTemplates.class)){
- String mappingPath = ((DynamicTemplates) clazz.getAnnotation(DynamicTemplates.class)).mappingPath();
+ private void addDynamicTemplatesMapping(XContentBuilder builder, ElasticsearchPersistentEntity> entity)
+ throws IOException {
+
+ if (entity.isAnnotationPresent(DynamicTemplates.class)) {
+ String mappingPath = entity.getRequiredAnnotation(DynamicTemplates.class).mappingPath();
if (hasText(mappingPath)) {
+
String jsonString = ElasticsearchTemplate.readFileFromClasspath(mappingPath);
if (hasText(jsonString)) {
+
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(jsonString).get("dynamic_templates");
- if (jsonNode != null && jsonNode.isArray()){
+ if (jsonNode != null && jsonNode.isArray()) {
String json = objectMapper.writeValueAsString(jsonNode);
builder.rawField(FIELD_DYNAMIC_TEMPLATES, new ByteArrayInputStream(json.getBytes()), XContentType.JSON);
}
@@ -388,63 +417,33 @@ private static void addDynamicTemplatesMapping(XContentBuilder builder, Class>
}
}
- protected static boolean isEntity(java.lang.reflect.Field field) {
- TypeInformation> typeInformation = ClassTypeInformation.from(field.getType());
- Class> clazz = getFieldType(field);
- boolean isComplexType = !SIMPLE_TYPE_HOLDER.isSimpleType(clazz);
- return isComplexType && !Map.class.isAssignableFrom(typeInformation.getType());
- }
-
- protected static Class> getFieldType(java.lang.reflect.Field field) {
-
- ResolvableType resolvableType = ResolvableType.forField(field);
-
- if (resolvableType.isArray()) {
- return resolvableType.getComponentType().getRawClass();
- }
-
- ResolvableType componentType = resolvableType.getGeneric(0);
- if (Iterable.class.isAssignableFrom(field.getType())
- && componentType != ResolvableType.NONE) {
- return componentType.getRawClass();
- }
-
- return resolvableType.getRawClass();
- }
+ private boolean isAnyPropertyAnnotatedWithField(@Nullable ElasticsearchPersistentEntity entity) {
- private static boolean isAnyPropertyAnnotatedAsField(java.lang.reflect.Field[] fields) {
- if (fields != null) {
- for (java.lang.reflect.Field field : fields) {
- if (field.isAnnotationPresent(Field.class)) {
- return true;
- }
- }
- }
- return false;
+ return entity != null && entity.getPersistentProperty(Field.class) != null;
}
- private static boolean isIdField(java.lang.reflect.Field field, String idFieldName) {
- return idFieldName.equals(field.getName());
- }
+ private boolean isInIgnoreFields(ElasticsearchPersistentProperty property, @Nullable Field parentFieldAnnotation) {
- private static boolean isInIgnoreFields(java.lang.reflect.Field field, Field parentFieldAnnotation) {
if (null != parentFieldAnnotation) {
+
String[] ignoreFields = parentFieldAnnotation.ignoreFields();
- return Arrays.asList(ignoreFields).contains(field.getName());
+ return Arrays.asList(ignoreFields).contains(property.getFieldName());
}
return false;
}
- private static boolean isNestedOrObjectField(java.lang.reflect.Field field) {
- Field fieldAnnotation = field.getAnnotation(Field.class);
- return fieldAnnotation != null && (FieldType.Nested == fieldAnnotation.type() || FieldType.Object == fieldAnnotation.type());
+ private boolean isNestedOrObjectProperty(ElasticsearchPersistentProperty property) {
+
+ Field fieldAnnotation = property.findAnnotation(Field.class);
+ return fieldAnnotation != null
+ && (FieldType.Nested == fieldAnnotation.type() || FieldType.Object == fieldAnnotation.type());
}
- private static boolean isGeoPointField(java.lang.reflect.Field field) {
- return field.getType() == GeoPoint.class || field.getAnnotation(GeoPointField.class) != null;
+ private boolean isGeoPointProperty(ElasticsearchPersistentProperty property) {
+ return property.getActualType() == GeoPoint.class || property.isAnnotationPresent(GeoPointField.class);
}
- private static boolean isCompletionField(java.lang.reflect.Field field) {
- return field.getType() == Completion.class;
+ private boolean isCompletionProperty(ElasticsearchPersistentProperty property) {
+ return property.getActualType() == Completion.class;
}
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplateTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplateTests.java
index 2c7e8933c..35dfe29a0 100644
--- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplateTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplateTests.java
@@ -50,8 +50,8 @@ public void shouldThrowExceptionIfDocumentDoesNotExistWhileDoingPartialUpdate()
// when
IndexRequest indexRequest = new IndexRequest();
indexRequest.source("{}", XContentType.JSON);
- UpdateQuery updateQuery = new UpdateQueryBuilder().withId(randomNumeric(5))
- .withClass(SampleEntity.class).withIndexRequest(indexRequest).build();
+ UpdateQuery updateQuery = new UpdateQueryBuilder().withId(randomNumeric(5)).withClass(SampleEntity.class)
+ .withIndexRequest(indexRequest).build();
elasticsearchTemplate.update(updateQuery);
}
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java
index 4179c363e..d9e8e3500 100755
--- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java
@@ -90,8 +90,8 @@
* @author Peter Nowak
* @author Ivan Greene
* @author Dmitriy Yakovlev
+ * @author Peter-Josef Meisch
*/
-
@Ignore
public class ElasticsearchTemplateTests {
@@ -128,6 +128,8 @@ public AggregatedPage mapResults(SearchResponse response, Class clazz,
@Before
public void before() {
+ deleteIndices();
+
elasticsearchTemplate.createIndex(SampleEntity.class);
elasticsearchTemplate.putMapping(SampleEntity.class);
@@ -137,7 +139,10 @@ public void before() {
@After
public void after() {
+ deleteIndices();
+ }
+ private void deleteIndices() {
elasticsearchTemplate.deleteIndex(SampleEntity.class);
elasticsearchTemplate.deleteIndex(SampleEntityUUIDKeyed.class);
elasticsearchTemplate.deleteIndex(UseServerConfigurationEntity.class);
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/MappingBuilderTests.java b/src/test/java/org/springframework/data/elasticsearch/core/MappingBuilderTests.java
index 00cea87ea..dab674240 100644
--- a/src/test/java/org/springframework/data/elasticsearch/core/MappingBuilderTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/MappingBuilderTests.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.*;
import static org.springframework.data.elasticsearch.utils.IndexBuilder.*;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
@@ -29,25 +28,15 @@
import java.util.List;
import java.util.Map;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.builder.SampleInheritedEntityBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
-import org.springframework.data.elasticsearch.entities.Book;
-import org.springframework.data.elasticsearch.entities.CopyToEntity;
-import org.springframework.data.elasticsearch.entities.GeoEntity;
-import org.springframework.data.elasticsearch.entities.Group;
-import org.springframework.data.elasticsearch.entities.MinimalEntity;
-import org.springframework.data.elasticsearch.entities.NormalizerEntity;
-import org.springframework.data.elasticsearch.entities.SampleInheritedEntity;
-import org.springframework.data.elasticsearch.entities.SampleTransientEntity;
-import org.springframework.data.elasticsearch.entities.SimpleRecursiveEntity;
-import org.springframework.data.elasticsearch.entities.StockPrice;
-import org.springframework.data.elasticsearch.entities.User;
+import org.springframework.data.elasticsearch.entities.*;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -59,19 +48,14 @@
* @author Nordine Bittich
* @author Don Wellington
* @author Sascha Woo
+ * @author Peter-Josef Meisch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
-public class MappingBuilderTests {
+public class MappingBuilderTests extends MappingContextBaseTests {
@Autowired private ElasticsearchTemplate elasticsearchTemplate;
- private String xContentBuilderToString(XContentBuilder builder) {
- builder.close();
- ByteArrayOutputStream bos = (ByteArrayOutputStream) builder.getOutputStream();
- return bos.toString();
- }
-
@Test
public void shouldNotFailOnCircularReference() {
elasticsearchTemplate.deleteIndex(SimpleRecursiveEntity.class);
@@ -81,24 +65,25 @@ public void shouldNotFailOnCircularReference() {
}
@Test
- public void testInfiniteLoopAvoidance() throws IOException {
+ public void testInfiniteLoopAvoidance() throws IOException, JSONException {
final String expected = "{\"mapping\":{\"properties\":{\"message\":{\"store\":true,\""
+ "type\":\"text\",\"index\":false," + "\"analyzer\":\"standard\"}}}}";
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleTransientEntity.class, "mapping", "id", null);
- assertThat(xContentBuilderToString(xContentBuilder), is(expected));
+ String mapping = getMappingBuilder().buildMapping(SampleTransientEntity.class);
+
+ JSONAssert.assertEquals(expected, mapping, false);
}
@Test
- public void shouldUseValueFromAnnotationType() throws IOException {
+ public void shouldUseValueFromAnnotationType() throws IOException, JSONException {
// Given
- final String expected = "{\"mapping\":{\"properties\":{\"price\":{\"store\":false,\"type\":\"double\"}}}}";
+ final String expected = "{\"price\":{\"properties\":{\"price\":{\"store\":false,\"type\":\"double\"}}}}";
// When
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(StockPrice.class, "mapping", "id", null);
+ String mapping = getMappingBuilder().buildMapping(StockPrice.class);
// Then
- assertThat(xContentBuilderToString(xContentBuilder), is(expected));
+ JSONAssert.assertEquals(expected, mapping, false);
}
@Test // DATAES-530
@@ -127,23 +112,26 @@ public void shouldAddStockPriceDocumentToIndex() throws IOException {
}
@Test
- public void shouldCreateMappingForSpecifiedParentType() throws IOException {
+ public void shouldCreateMappingForSpecifiedParentType() throws IOException, JSONException {
final String expected = "{\"mapping\":{\"_parent\":{\"type\":\"parentType\"},\"properties\":{}}}";
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(MinimalEntity.class, "mapping", "id", "parentType");
- assertThat(xContentBuilderToString(xContentBuilder), is(expected));
+
+ String mapping = getMappingBuilder().buildMapping(MinimalChildEntity.class);
+
+ JSONAssert.assertEquals(expected, mapping, false);
}
/*
* DATAES-76
*/
@Test
- public void shouldBuildMappingWithSuperclass() throws IOException {
+ public void shouldBuildMappingWithSuperclass() throws IOException, JSONException {
final String expected = "{\"mapping\":{\"properties\":{\"message\":{\"store\":true,\""
+ "type\":\"text\",\"index\":false,\"analyzer\":\"standard\"}" + ",\"createdDate\":{\"store\":false,"
+ "\"type\":\"date\",\"index\":false}}}}";
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleInheritedEntity.class, "mapping", "id", null);
- assertThat(xContentBuilderToString(xContentBuilder), is(expected));
+ String mapping = getMappingBuilder().buildMapping(SampleInheritedEntity.class);
+
+ JSONAssert.assertEquals(expected, mapping, false);
}
/*
@@ -174,19 +162,18 @@ public void shouldAddSampleInheritedEntityDocumentToIndex() throws IOException {
}
@Test
- public void shouldBuildMappingsForGeoPoint() throws IOException {
+ public void shouldBuildMappingsForGeoPoint() throws IOException, JSONException {
// given
+ String expected = "{\"geo-test-index\": {\"properties\": {" + "\"pointA\":{\"type\":\"geo_point\"},"
+ + "\"pointB\":{\"type\":\"geo_point\"}," + "\"pointC\":{\"type\":\"geo_point\"},"
+ + "\"pointD\":{\"type\":\"geo_point\"}" + "}}}";
// when
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(GeoEntity.class, "mapping", "id", null);
+ String mapping;
+ mapping = getMappingBuilder().buildMapping(GeoEntity.class);
// then
- final String result = xContentBuilderToString(xContentBuilder);
-
- assertThat(result, containsString("\"pointA\":{\"type\":\"geo_point\""));
- assertThat(result, containsString("\"pointB\":{\"type\":\"geo_point\""));
- assertThat(result, containsString("\"pointC\":{\"type\":\"geo_point\""));
- assertThat(result, containsString("\"pointD\":{\"type\":\"geo_point\""));
+ JSONAssert.assertEquals(expected, mapping, false);
}
/**
@@ -276,4 +263,103 @@ public void shouldUseCopyTo() throws IOException {
assertThat(fieldFirstName.get("copy_to"), equalTo(copyToValue));
assertThat(fieldLastName.get("copy_to"), equalTo(copyToValue));
}
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnId() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true}" + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.IdEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnText() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true},"
+ + "\"text-property\":{\"store\":false,\"type\":\"text\"}" + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.TextEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnMapping() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true},"
+ + "\"mapping-property\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}" + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.MappingEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnGeoPoint() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true}," + "\"geopoint-property\":{\"type\":\"geo_point\"}"
+ + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.GeoPointEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnCircularEntity() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true},"
+ + "\"circular-property\":{\"type\":\"object\",\"properties\":{\"id-property\":{\"store\":false}}}" + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.CircularEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnCompletion() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true},"
+ + "\"completion-property\":{\"type\":\"completion\",\"max_input_length\":100,\"preserve_position_increments\":true,\"preserve_separators\":true,\"search_analyzer\":\"simple\",\"analyzer\":\"simple\"},\"completion-property\":{\"store\":false}"
+ + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.CompletionEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
+
+ @Test // DATAES-568
+ public void shouldUseFieldNameOnMultiField() throws IOException, JSONException {
+ // given
+ final String expected = "{\"fieldname-type\":{\"properties\":{"
+ + "\"id-property\":{\"type\":\"keyword\",\"index\":true},"
+ + "\"multifield-property\":{\"store\":false,\"type\":\"text\",\"analyzer\":\"whitespace\",\"fields\":{\"prefix\":{\"store\":false,\"type\":\"text\",\"analyzer\":\"stop\",\"search_analyzer\":\"standard\"}}}"
+ + "}}}";
+
+ // when
+ String mapping = getMappingBuilder().buildMapping(FieldNameEntity.MultiFieldEntity.class);
+
+ // then
+ JSONAssert.assertEquals(expected, mapping, false);
+ }
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/MappingContextBaseTests.java b/src/test/java/org/springframework/data/elasticsearch/core/MappingContextBaseTests.java
new file mode 100644
index 000000000..dbac910d3
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/core/MappingContextBaseTests.java
@@ -0,0 +1,54 @@
+/* Copyright 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.elasticsearch.core;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
+import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
+import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
+import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
+import org.springframework.data.util.Lazy;
+
+/**
+ * @author Peter-Josef Meisch
+ */
+abstract class MappingContextBaseTests {
+
+ protected final Lazy elasticsearchConverter = Lazy.of(this::setupElasticsearchConverter);
+
+ private ElasticsearchConverter setupElasticsearchConverter() {
+ return new MappingElasticsearchConverter(setupMappingContext());
+ }
+
+ private SimpleElasticsearchMappingContext setupMappingContext() {
+
+ SimpleElasticsearchMappingContext mappingContext = new ElasticsearchConfigurationSupport() {
+ @Override
+ protected Collection getMappingBasePackages() {
+ return Collections.singletonList("org.springframework.data.elasticsearch.entities.mapping");
+ }
+ }.elasticsearchMappingContext();
+
+ mappingContext.initialize();
+ return mappingContext;
+ }
+
+ final MappingBuilder getMappingBuilder() {
+ return new MappingBuilder(elasticsearchConverter.get());
+ }
+}
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/SimpleDynamicTemplatesMappingTests.java b/src/test/java/org/springframework/data/elasticsearch/core/SimpleDynamicTemplatesMappingTests.java
index 586223859..71ddaa90d 100644
--- a/src/test/java/org/springframework/data/elasticsearch/core/SimpleDynamicTemplatesMappingTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/SimpleDynamicTemplatesMappingTests.java
@@ -2,8 +2,6 @@
import java.io.IOException;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.xcontent.XContentBuilder;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -16,35 +14,32 @@
* Dynamic templates tests
*
* @author Petr Kukral
+ * @author Peter-Josef Meisch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
-public class SimpleDynamicTemplatesMappingTests {
+public class SimpleDynamicTemplatesMappingTests extends MappingContextBaseTests {
@Test
public void testCorrectDynamicTemplatesMappings() throws IOException {
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleDynamicTemplatesEntity.class,
- "test-dynamictemplatestype", "id", null);
- String EXPECTED_MAPPING_ONE = "{\"test-dynamictemplatestype\":{\"dynamic_templates\":" +
- "[{\"with_custom_analyzer\":{" +
- "\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}," +
- "\"path_match\":\"names.*\"}}]," +
- "\"properties\":{\"names\":{\"type\":\"object\"}}}}";
- Assert.assertEquals(EXPECTED_MAPPING_ONE, Strings.toString(xContentBuilder));
+ String mapping = getMappingBuilder().buildMapping(SampleDynamicTemplatesEntity.class);
+
+ String EXPECTED_MAPPING_ONE = "{\"test-dynamictemplatestype\":{\"dynamic_templates\":"
+ + "[{\"with_custom_analyzer\":{"
+ + "\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"},"
+ + "\"path_match\":\"names.*\"}}]," + "\"properties\":{\"names\":{\"type\":\"object\"}}}}";
+ Assert.assertEquals(EXPECTED_MAPPING_ONE, mapping);
}
@Test
public void testCorrectDynamicTemplatesMappingsTwo() throws IOException {
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleDynamicTemplatesEntityTwo.class,
- "test-dynamictemplatestype", "id", null);
- String EXPECTED_MAPPING_TWO = "{\"test-dynamictemplatestype\":{\"dynamic_templates\":" +
- "[{\"with_custom_analyzer\":{" +
- "\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}," +
- "\"path_match\":\"names.*\"}}," +
- "{\"participantA1_with_custom_analyzer\":{" +
- "\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}," +
- "\"path_match\":\"participantA1.*\"}}]," +
- "\"properties\":{\"names\":{\"type\":\"object\"}}}}";
- Assert.assertEquals(EXPECTED_MAPPING_TWO, Strings.toString(xContentBuilder));
+ String mapping = getMappingBuilder().buildMapping(SampleDynamicTemplatesEntityTwo.class);
+ String EXPECTED_MAPPING_TWO = "{\"test-dynamictemplatestype\":{\"dynamic_templates\":"
+ + "[{\"with_custom_analyzer\":{"
+ + "\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"},"
+ + "\"path_match\":\"names.*\"}}," + "{\"participantA1_with_custom_analyzer\":{"
+ + "\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"},"
+ + "\"path_match\":\"participantA1.*\"}}]," + "\"properties\":{\"names\":{\"type\":\"object\"}}}}";
+ Assert.assertEquals(EXPECTED_MAPPING_TWO, mapping);
}
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/SimpleElasticsearchDateMappingTests.java b/src/test/java/org/springframework/data/elasticsearch/core/SimpleElasticsearchDateMappingTests.java
index f090a54a2..bdce10abf 100644
--- a/src/test/java/org/springframework/data/elasticsearch/core/SimpleElasticsearchDateMappingTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/SimpleElasticsearchDateMappingTests.java
@@ -15,11 +15,8 @@
*/
package org.springframework.data.elasticsearch.core;
-import java.beans.IntrospectionException;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import org.elasticsearch.common.xcontent.XContentBuilder;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.data.elasticsearch.entities.SampleDateMappingEntity;
@@ -28,20 +25,20 @@
* @author Jakub Vavrik
* @author Mohsin Husen
* @author Don Wellington
+ * @author Peter-Josef Meisch
*/
-public class SimpleElasticsearchDateMappingTests {
+public class SimpleElasticsearchDateMappingTests extends MappingContextBaseTests {
- private static final String EXPECTED_MAPPING = "{\"mapping\":{\"properties\":{\"message\":{\"store\":true," +
- "\"type\":\"text\",\"index\":false,\"analyzer\":\"standard\"},\"customFormatDate\":{\"store\":false,\"type\":\"date\",\"format\":\"dd.MM.yyyy hh:mm\"}," +
- "\"defaultFormatDate\":{\"store\":false,\"type\":\"date\"},\"basicFormatDate\":{\"store\":false,\"" +
- "type\":\"date\",\"format\":\"basic_date\"}}}}";
+ private static final String EXPECTED_MAPPING = "{\"mapping\":{\"properties\":{\"message\":{\"store\":true,"
+ + "\"type\":\"text\",\"index\":false,\"analyzer\":\"standard\"},\"customFormatDate\":{\"store\":false,\"type\":\"date\",\"format\":\"dd.MM.yyyy hh:mm\"},"
+ + "\"defaultFormatDate\":{\"store\":false,\"type\":\"date\"},\"basicFormatDate\":{\"store\":false,\""
+ + "type\":\"date\",\"format\":\"basic_date\"}}}}";
@Test
- public void testCorrectDateMappings() throws NoSuchFieldException, IntrospectionException, IOException {
- XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleDateMappingEntity.class, "mapping", "id", null);
- xContentBuilder.close();
- ByteArrayOutputStream bos = (ByteArrayOutputStream) xContentBuilder.getOutputStream();
- String result = bos.toString();
- Assert.assertEquals(EXPECTED_MAPPING, result);
+ public void testCorrectDateMappings() throws IOException {
+
+ String mapping = getMappingBuilder().buildMapping(SampleDateMappingEntity.class);
+
+ Assert.assertEquals(EXPECTED_MAPPING, mapping);
}
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/entities/FieldNameEntity.java b/src/test/java/org/springframework/data/elasticsearch/entities/FieldNameEntity.java
new file mode 100644
index 000000000..d5fc2e1cd
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/entities/FieldNameEntity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */package org.springframework.data.elasticsearch.entities;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.elasticsearch.annotations.CompletionField;
+import org.springframework.data.elasticsearch.annotations.Document;
+import org.springframework.data.elasticsearch.annotations.Field;
+import org.springframework.data.elasticsearch.annotations.FieldType;
+import org.springframework.data.elasticsearch.annotations.InnerField;
+import org.springframework.data.elasticsearch.annotations.Mapping;
+import org.springframework.data.elasticsearch.annotations.MultiField;
+import org.springframework.data.elasticsearch.core.completion.Completion;
+import org.springframework.data.elasticsearch.core.geo.GeoPoint;
+
+/**
+ * @author Peter-Josef Meisch
+ */
+public class FieldNameEntity {
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class IdEntity {
+ @Id @Field("id-property")
+ private String id;
+ }
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class TextEntity {
+
+ @Id @Field("id-property")
+ private String id;
+
+ @Field(name = "text-property", type = FieldType.Text)
+ private String textProperty;
+ }
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class MappingEntity {
+
+ @Id @Field("id-property")
+ private String id;
+
+ @Field("mapping-property") @Mapping(mappingPath = "/mappings/test-field-analyzed-mappings.json")
+ private byte[] mappingProperty;
+ }
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class GeoPointEntity {
+
+ @Id @Field("id-property")
+ private String id;
+
+ @Field("geopoint-property")
+ private GeoPoint geoPoint;
+ }
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class CircularEntity {
+
+ @Id @Field("id-property")
+ private String id;
+
+ @Field(name = "circular-property", type = FieldType.Object,
+ ignoreFields = { "circular-property" })
+ private CircularEntity circularProperty;
+ }
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class CompletionEntity {
+
+ @Id @Field("id-property")
+ private String id;
+
+ @Field("completion-property")
+ @CompletionField(maxInputLength = 100)
+ private Completion suggest;
+ }
+
+ @Document(indexName = "fieldname-index", type = "fieldname-type")
+ public static class MultiFieldEntity {
+
+ @Id @Field("id-property")
+ private String id;
+
+ @Field("multifield-property")
+ @MultiField(
+ mainField = @Field(type = FieldType.Text, analyzer = "whitespace"),
+ otherFields = {
+ @InnerField(suffix = "prefix", type = FieldType.Text, analyzer = "stop", searchAnalyzer = "standard")
+ }
+ )
+ private String description;
+ }
+}
diff --git a/src/test/java/org/springframework/data/elasticsearch/entities/MinimalChildEntity.java b/src/test/java/org/springframework/data/elasticsearch/entities/MinimalChildEntity.java
new file mode 100644
index 000000000..7172dc10e
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/entities/MinimalChildEntity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.elasticsearch.entities;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.elasticsearch.annotations.Document;
+import org.springframework.data.elasticsearch.annotations.Parent;
+
+/**
+ * MinimalChildEntity
+ *
+ * @author Peter-josef Meisch
+ */
+@Document(indexName = "test-index-minimal", type = "mapping")
+public class MinimalChildEntity {
+
+ @Id
+ private String id;
+
+ @Parent(type = "parentType")
+ private String parentId;
+}
diff --git a/src/test/resources/mappings/test-field-analyzed-mappings.json b/src/test/resources/mappings/test-field-analyzed-mappings.json
new file mode 100644
index 000000000..cce7b3e99
--- /dev/null
+++ b/src/test/resources/mappings/test-field-analyzed-mappings.json
@@ -0,0 +1,4 @@
+{
+ "type": "string",
+ "analyzer": "standard_lowercase_asciifolding"
+}