mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-05-29 08:12:11 +00:00
parent
b7a23ed7f1
commit
aba14c5e11
@ -15,7 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
|
||||
/**
|
||||
@ -26,9 +31,15 @@ import org.springframework.data.annotation.Persistent;
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD })
|
||||
public @interface Mapping {
|
||||
|
||||
String mappingPath() default "";
|
||||
|
||||
/**
|
||||
* whether mappings are enabled
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean enabled() default true;
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ 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.ElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.annotations.*;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ResourceUtil;
|
||||
@ -66,6 +65,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
*/
|
||||
public class MappingBuilder {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ElasticsearchRestTemplate.class);
|
||||
|
||||
private static final String FIELD_INDEX = "index";
|
||||
private static final String FIELD_PROPERTIES = "properties";
|
||||
@Deprecated private static final String FIELD_PARENT = "_parent";
|
||||
@ -88,7 +89,7 @@ public class MappingBuilder {
|
||||
|
||||
private static final String JOIN_TYPE_RELATIONS = "relations";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ElasticsearchRestTemplate.class);
|
||||
private static final String MAPPING_ENABLED = "enabled";
|
||||
|
||||
private final ElasticsearchConverter elasticsearchConverter;
|
||||
|
||||
@ -100,9 +101,9 @@ public class MappingBuilder {
|
||||
* builds the Elasticsearch mapping for the given clazz.
|
||||
*
|
||||
* @return JSON string
|
||||
* @throws ElasticsearchException on errors while building the mapping
|
||||
* @throws MappingException on errors while building the mapping
|
||||
*/
|
||||
public String buildPropertyMapping(Class<?> clazz) throws ElasticsearchException {
|
||||
public String buildPropertyMapping(Class<?> clazz) throws MappingException {
|
||||
|
||||
try {
|
||||
ElasticsearchPersistentEntity<?> entity = elasticsearchConverter.getMappingContext()
|
||||
@ -125,8 +126,8 @@ public class MappingBuilder {
|
||||
.close();
|
||||
|
||||
return builder.getOutputStream().toString();
|
||||
} catch (MappingException | IOException e) {
|
||||
throw new ElasticsearchException("could not build mapping", e);
|
||||
} catch (IOException e) {
|
||||
throw new MappingException("could not build mapping", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +135,14 @@ public class MappingBuilder {
|
||||
boolean isRootObject, String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType,
|
||||
@Nullable Field parentFieldAnnotation, @Nullable DynamicMapping dynamicMapping) throws IOException {
|
||||
|
||||
if (entity != null && entity.isAnnotationPresent(Mapping.class)) {
|
||||
|
||||
if (!entity.getRequiredAnnotation(Mapping.class).enabled()) {
|
||||
builder.field(MAPPING_ENABLED, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
|
||||
if (writeNestedProperties) {
|
||||
|
||||
@ -189,14 +198,22 @@ public class MappingBuilder {
|
||||
|
||||
if (property.isAnnotationPresent(Mapping.class)) {
|
||||
|
||||
String mappingPath = property.getRequiredAnnotation(Mapping.class).mappingPath();
|
||||
if (!StringUtils.isEmpty(mappingPath)) {
|
||||
Mapping mapping = property.getRequiredAnnotation(Mapping.class);
|
||||
|
||||
ClassPathResource mappings = new ClassPathResource(mappingPath);
|
||||
if (mappings.exists()) {
|
||||
builder.rawField(property.getFieldName(), mappings.getInputStream(), XContentType.JSON);
|
||||
return;
|
||||
if (mapping.enabled()) {
|
||||
String mappingPath = mapping.mappingPath();
|
||||
|
||||
if (StringUtils.hasText(mappingPath)) {
|
||||
|
||||
ClassPathResource mappings = new ClassPathResource(mappingPath);
|
||||
if (mappings.exists()) {
|
||||
builder.rawField(property.getFieldName(), mappings.getInputStream(), XContentType.JSON);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
applyDisabledPropertyMapping(builder, property);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,9 +334,29 @@ public class MappingBuilder {
|
||||
|
||||
private void applyDefaultIdFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
|
||||
throws IOException {
|
||||
builder.startObject(property.getFieldName()) //
|
||||
.field(FIELD_PARAM_TYPE, TYPE_VALUE_KEYWORD) //
|
||||
.field(FIELD_INDEX, true) //
|
||||
.endObject(); //
|
||||
}
|
||||
|
||||
builder.startObject(property.getFieldName()).field(FIELD_PARAM_TYPE, TYPE_VALUE_KEYWORD).field(FIELD_INDEX, true)
|
||||
.endObject();
|
||||
private void applyDisabledPropertyMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
|
||||
throws IOException {
|
||||
|
||||
try {
|
||||
Field field = property.getRequiredAnnotation(Field.class);
|
||||
|
||||
if (field.type() != FieldType.Object) {
|
||||
throw new IllegalArgumentException("Field type must be 'object");
|
||||
}
|
||||
|
||||
builder.startObject(property.getFieldName()) //
|
||||
.field(FIELD_PARAM_TYPE, field.type().name().toLowerCase()) //
|
||||
.field(MAPPING_ENABLED, false) //
|
||||
.endObject(); //
|
||||
} catch (Exception e) {
|
||||
throw new MappingException("Could not write enabled: false mapping for " + property.getFieldName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,7 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.lang.Integer;
|
||||
import java.lang.Object;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -268,9 +269,26 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
indexOps.putMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Xiao Yu
|
||||
*/
|
||||
@Test // #1370
|
||||
@DisplayName("should write mapping for disabled entity")
|
||||
void shouldWriteMappingForDisabledEntity() {
|
||||
|
||||
IndexOperations indexOps = operations.indexOps(DisabledMappingEntity.class);
|
||||
indexOps.create();
|
||||
indexOps.putMapping();
|
||||
indexOps.delete();
|
||||
}
|
||||
|
||||
@Test // #1370
|
||||
@DisplayName("should write mapping for disabled property")
|
||||
void shouldWriteMappingForDisabledProperty() {
|
||||
|
||||
IndexOperations indexOps = operations.indexOps(DisabledMappingProperty.class);
|
||||
indexOps.create();
|
||||
indexOps.putMapping();
|
||||
indexOps.delete();
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -284,9 +302,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Keyword, ignoreAbove = 10) private String message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
static class FieldNameEntity {
|
||||
|
||||
@Document(indexName = "fieldname-index")
|
||||
@ -351,11 +366,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Nordine Bittich
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -373,10 +383,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
searchAnalyzer = "standard") }) private String description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Stuart Stevenson
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
@Data
|
||||
@Document(indexName = "test-index-simple-recursive-mapping-builder", replicas = 0, refreshInterval = "-1")
|
||||
static class SimpleRecursiveEntity {
|
||||
@ -386,9 +392,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
ignoreFields = { "circularObject" }) private SimpleRecursiveEntity circularObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -406,9 +409,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Keyword) private String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -426,10 +426,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
type = FieldType.Keyword, normalizer = "lower_case_normalizer") }) private String description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
static class Author {
|
||||
|
||||
@Nullable private String id;
|
||||
@ -454,9 +450,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
@Document(indexName = "test-index-sample-inherited-mapping-builder", replicas = 0, refreshInterval = "-1")
|
||||
static class SampleInheritedEntity extends AbstractInheritedEntity {
|
||||
|
||||
@ -472,9 +465,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
static class SampleInheritedEntityBuilder {
|
||||
|
||||
private final SampleInheritedEntity result;
|
||||
@ -506,10 +496,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -525,9 +511,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Double) private BigDecimal price;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Kevin Letur
|
||||
*/
|
||||
static class AbstractInheritedEntity {
|
||||
|
||||
@Nullable @Id private String id;
|
||||
@ -580,9 +563,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
orientation = GeoShapeField.Orientation.clockwise) private String shape2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by akonczak on 21/08/2016.
|
||||
*/
|
||||
@Document(indexName = "test-index-user-mapping-builder")
|
||||
static class User {
|
||||
@Nullable @Id private String id;
|
||||
@ -590,9 +570,6 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Nested, ignoreFields = { "users" }) private Set<Group> groups = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by akonczak on 21/08/2016.
|
||||
*/
|
||||
@Document(indexName = "test-index-group-mapping-builder")
|
||||
static class Group {
|
||||
|
||||
@ -662,4 +639,20 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
@Nullable @Field(type = Wildcard) private String wildcardWithoutParams;
|
||||
@Nullable @Field(type = Wildcard, nullValue = "WILD", ignoreAbove = 42) private String wildcardWithParams;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Document(indexName = "disabled-entity-mapping")
|
||||
@Mapping(enabled = false)
|
||||
static class DisabledMappingEntity {
|
||||
@Id private String id;
|
||||
@Field(type = Text) private String text;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Document(indexName = "disabled-property-mapping")
|
||||
static class DisabledMappingProperty {
|
||||
@Id private String id;
|
||||
@Field(type = Text) private String text;
|
||||
@Mapping(enabled = false) @Field(type = Object) private Object object;
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@ -504,9 +505,49 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
assertEquals(expected, mapping, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Xiao Yu
|
||||
*/
|
||||
@Test // #1370
|
||||
@DisplayName("should not write mapping when enabled is false on entity")
|
||||
void shouldNotWriteMappingWhenEnabledIsFalseOnEntity() throws JSONException {
|
||||
|
||||
String expected = "{\n" + //
|
||||
" \"enabled\": false" + //
|
||||
"}";
|
||||
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(DisabledMappingEntity.class);
|
||||
|
||||
assertEquals(expected, mapping, false);
|
||||
}
|
||||
|
||||
@Test // #1370
|
||||
@DisplayName("should write disabled property mapping")
|
||||
void shouldWriteDisabledPropertyMapping() throws JSONException {
|
||||
|
||||
String expected = "{\n" + //
|
||||
" \"properties\":{\n" + //
|
||||
" \"text\": {\n" + //
|
||||
" \"type\": \"text\"\n" + //
|
||||
" },\n" + //
|
||||
" \"object\": {\n" + //
|
||||
" \"type\": \"object\",\n" + //
|
||||
" \"enabled\": false\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}\n"; //
|
||||
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(DisabledMappingProperty.class);
|
||||
|
||||
assertEquals(expected, mapping, false);
|
||||
}
|
||||
|
||||
@Test // #1370
|
||||
@DisplayName("should only allow disabled properties on type object")
|
||||
void shouldOnlyAllowDisabledPropertiesOnTypeObject() {
|
||||
|
||||
assertThatThrownBy(() ->
|
||||
getMappingBuilder().buildPropertyMapping(InvalidDisabledMappingProperty.class)
|
||||
).isInstanceOf(MappingException.class);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -520,9 +561,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Keyword, ignoreAbove = 10) private String message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
static class FieldNameEntity {
|
||||
|
||||
@Document(indexName = "fieldname-index")
|
||||
@ -587,11 +625,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Nordine Bittich
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -609,10 +642,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
searchAnalyzer = "standard") }) private String description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Stuart Stevenson
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
@Data
|
||||
@Document(indexName = "test-index-simple-recursive-mapping-builder", replicas = 0, refreshInterval = "-1")
|
||||
static class SimpleRecursiveEntity {
|
||||
@ -622,9 +651,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
ignoreFields = { "circularObject" }) private SimpleRecursiveEntity circularObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -642,9 +668,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Keyword) private String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -662,10 +685,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
type = FieldType.Keyword, normalizer = "lower_case_normalizer") }) private String description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
static class Author {
|
||||
|
||||
@Nullable private String id;
|
||||
@ -690,9 +709,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
@Document(indexName = "test-index-sample-inherited-mapping-builder", replicas = 0, refreshInterval = "-1")
|
||||
static class SampleInheritedEntity extends AbstractInheritedEntity {
|
||||
|
||||
@ -708,10 +724,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -727,9 +739,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Double) private BigDecimal price;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Kevin Letur
|
||||
*/
|
||||
static class AbstractInheritedEntity {
|
||||
|
||||
@Nullable @Id private String id;
|
||||
@ -755,9 +764,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jakub Vavrik
|
||||
*/
|
||||
@Document(indexName = "test-index-recursive-mapping-mapping-builder", replicas = 0, refreshInterval = "-1")
|
||||
static class SampleTransientEntity {
|
||||
|
||||
@ -836,9 +842,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
orientation = GeoShapeField.Orientation.clockwise) private String shape2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by akonczak on 21/08/2016.
|
||||
*/
|
||||
@Document(indexName = "test-index-user-mapping-builder")
|
||||
static class User {
|
||||
@Nullable @Id private String id;
|
||||
@ -846,9 +849,6 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Nested, ignoreFields = { "users" }) private Set<Group> groups = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by akonczak on 21/08/2016.
|
||||
*/
|
||||
@Document(indexName = "test-index-group-mapping-builder")
|
||||
static class Group {
|
||||
|
||||
@ -961,4 +961,26 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
@Field(type = FieldType.Rank_Feature, positiveScoreImpact = false) private Integer urlLength;
|
||||
@Field(type = FieldType.Rank_Features) private Map<String, Integer> topics;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Mapping(enabled = false)
|
||||
static class DisabledMappingEntity {
|
||||
@Id private String id;
|
||||
@Field(type = Text) private String text;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class InvalidDisabledMappingProperty {
|
||||
@Id private String id;
|
||||
@Mapping(enabled = false)
|
||||
@Field(type = Text) private String text;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class DisabledMappingProperty {
|
||||
@Id private String id;
|
||||
@Field(type = Text) private String text;
|
||||
@Mapping(enabled = false)
|
||||
@Field(type = Object) private Object object;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user