diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java new file mode 100644 index 000000000..122251ee6 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 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 + * + * http://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.annotations; + +import java.lang.annotation.*; +import org.springframework.data.annotation.Persistent; + +/** + * Elasticsearch Mapping + * + * @author Mohsin Husen + */ +@Persistent +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface Mapping { + + String mappingPath() default ""; + +} 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 dda614e68..60372ef00 100755 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -75,6 +75,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.ElasticsearchException; import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Mapping; import org.springframework.data.elasticsearch.annotations.Setting; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter; @@ -138,6 +139,17 @@ public class ElasticsearchTemplate implements ElasticsearchOperations { @Override public boolean putMapping(Class clazz) { + if (clazz.isAnnotationPresent(Mapping.class)) { + String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath(); + if (isNotBlank(mappingPath)) { + String mappings = readFileFromClasspath(mappingPath); + if (isNotBlank(mappings)) { + return putMapping(clazz, mappings); + } + } else { + logger.info("mappingPath in @Mapping has to be defined. Building mappings using @Field"); + } + } ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz); XContentBuilder xContentBuilder = null; try { diff --git a/src/test/java/org/springframework/data/elasticsearch/entities/SettingEntity.java b/src/test/java/org/springframework/data/elasticsearch/entities/DynamicSettingAndMappingEntity.java similarity index 72% rename from src/test/java/org/springframework/data/elasticsearch/entities/SettingEntity.java rename to src/test/java/org/springframework/data/elasticsearch/entities/DynamicSettingAndMappingEntity.java index 9d83acd0f..ae053758c 100644 --- a/src/test/java/org/springframework/data/elasticsearch/entities/SettingEntity.java +++ b/src/test/java/org/springframework/data/elasticsearch/entities/DynamicSettingAndMappingEntity.java @@ -16,24 +16,21 @@ 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.Field; -import org.springframework.data.elasticsearch.annotations.FieldType; -import org.springframework.data.elasticsearch.annotations.Setting; +import org.springframework.data.elasticsearch.annotations.*; /** - * Sample SettingEntity for test out dynamic setting using @Setting Annotation + * Sample DynamicSettingAndMappingEntity for test out dynamic setting using @Setting Annotation * * @author Mohsin Husen */ -@Setting(settingPath = "/settings/test-settings.json") @Document(indexName = "test-setting-index", type = "test-setting-type") -public class SettingEntity { +@Setting(settingPath = "/settings/test-settings.json") +@Mapping(mappingPath = "/mappings/test-mappings.json") +public class DynamicSettingAndMappingEntity { @Id private String id; private String name; - @Field(type = FieldType.String, searchAnalyzer = "emailAnalyzer", indexAnalyzer = "emailAnalyzer") private String email; public String getId() { diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/setting/SettingEntityRepository.java b/src/test/java/org/springframework/data/elasticsearch/repositories/setting/DynamicSettingAndMappingEntityRepository.java similarity index 75% rename from src/test/java/org/springframework/data/elasticsearch/repositories/setting/SettingEntityRepository.java rename to src/test/java/org/springframework/data/elasticsearch/repositories/setting/DynamicSettingAndMappingEntityRepository.java index ba299b97d..778627642 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repositories/setting/SettingEntityRepository.java +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/setting/DynamicSettingAndMappingEntityRepository.java @@ -15,14 +15,14 @@ */ package org.springframework.data.elasticsearch.repositories.setting; -import org.springframework.data.elasticsearch.entities.SettingEntity; +import org.springframework.data.elasticsearch.entities.DynamicSettingAndMappingEntity; import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository; /** - * SettingEntityRepository + * DynamicSettingAndMappingEntityRepository * * @author Mohsin Husen */ -public interface SettingEntityRepository extends ElasticsearchCrudRepository { +public interface DynamicSettingAndMappingEntityRepository extends ElasticsearchCrudRepository { } diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/setting/SettingEntityRepositoryTest.java b/src/test/java/org/springframework/data/elasticsearch/repositories/setting/DynamicSettingAndMappingEntityRepositoryTests.java similarity index 55% rename from src/test/java/org/springframework/data/elasticsearch/repositories/setting/SettingEntityRepositoryTest.java rename to src/test/java/org/springframework/data/elasticsearch/repositories/setting/DynamicSettingAndMappingEntityRepositoryTests.java index 03f5746dc..128d64e8d 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repositories/setting/SettingEntityRepositoryTest.java +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/setting/DynamicSettingAndMappingEntityRepositoryTests.java @@ -30,31 +30,31 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.elasticsearch.core.query.SearchQuery; -import org.springframework.data.elasticsearch.entities.SettingEntity; +import org.springframework.data.elasticsearch.entities.DynamicSettingAndMappingEntity; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** - * SettingEntityRepositoryTest + * DynamicSettingAndMappingEntityRepositoryTests * * @author Mohsin Husen */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:dynamic-settings-test.xml") -public class SettingEntityRepositoryTest { +public class DynamicSettingAndMappingEntityRepositoryTests { @Autowired - private SettingEntityRepository repository; + private DynamicSettingAndMappingEntityRepository repository; @Autowired private ElasticsearchTemplate elasticsearchTemplate; @Before public void before() { - elasticsearchTemplate.deleteIndex(SettingEntity.class); - elasticsearchTemplate.createIndex(SettingEntity.class); - elasticsearchTemplate.putMapping(SettingEntity.class); - elasticsearchTemplate.refresh(SettingEntity.class, true); + elasticsearchTemplate.deleteIndex(DynamicSettingAndMappingEntity.class); + elasticsearchTemplate.createIndex(DynamicSettingAndMappingEntity.class); + elasticsearchTemplate.putMapping(DynamicSettingAndMappingEntity.class); + elasticsearchTemplate.refresh(DynamicSettingAndMappingEntity.class, true); } /* @@ -66,8 +66,8 @@ public class SettingEntityRepositoryTest { //delete , create and apply mapping in before method // then - assertThat(elasticsearchTemplate.indexExists(SettingEntity.class), is(true)); - Map map = elasticsearchTemplate.getSetting(SettingEntity.class); + assertThat(elasticsearchTemplate.indexExists(DynamicSettingAndMappingEntity.class), is(true)); + Map map = elasticsearchTemplate.getSetting(DynamicSettingAndMappingEntity.class); assertThat(map.containsKey("index.number_of_replicas"), is(true)); assertThat(map.containsKey("index.number_of_shards"), is(true)); assertThat(map.containsKey("index.analysis.analyzer.emailAnalyzer.tokenizer"), is(true)); @@ -82,32 +82,32 @@ public class SettingEntityRepositoryTest { @Test public void shouldSearchOnGivenTokenizerUsingGivenDynamicSettingsForGivenIndex() { //given - SettingEntity settingEntity1 = new SettingEntity(); - settingEntity1.setId(RandomStringUtils.randomNumeric(5)); - settingEntity1.setName("test-setting1"); - settingEntity1.setEmail("test_setting1@test.com"); + DynamicSettingAndMappingEntity dynamicSettingAndMappingEntity1 = new DynamicSettingAndMappingEntity(); + dynamicSettingAndMappingEntity1.setId(RandomStringUtils.randomNumeric(5)); + dynamicSettingAndMappingEntity1.setName("test-setting1"); + dynamicSettingAndMappingEntity1.setEmail("test_setting1@test.com"); - repository.save(settingEntity1); + repository.save(dynamicSettingAndMappingEntity1); - SettingEntity settingEntity2 = new SettingEntity(); - settingEntity2.setId(RandomStringUtils.randomNumeric(5)); - settingEntity2.setName("test-setting2"); - settingEntity2.setEmail("test_setting2@test.com"); + DynamicSettingAndMappingEntity dynamicSettingAndMappingEntity2 = new DynamicSettingAndMappingEntity(); + dynamicSettingAndMappingEntity2.setId(RandomStringUtils.randomNumeric(5)); + dynamicSettingAndMappingEntity2.setName("test-setting2"); + dynamicSettingAndMappingEntity2.setEmail("test_setting2@test.com"); - repository.save(settingEntity2); + repository.save(dynamicSettingAndMappingEntity2); //when SearchQuery searchQuery = new NativeSearchQueryBuilder() - .withQuery(QueryBuilders.termQuery("email", settingEntity1.getEmail())).build(); + .withQuery(QueryBuilders.termQuery("email", dynamicSettingAndMappingEntity1.getEmail())).build(); - long count = elasticsearchTemplate.count(searchQuery, SettingEntity.class); - List entityList = elasticsearchTemplate.queryForList(searchQuery, SettingEntity.class); + long count = elasticsearchTemplate.count(searchQuery, DynamicSettingAndMappingEntity.class); + List entityList = elasticsearchTemplate.queryForList(searchQuery, DynamicSettingAndMappingEntity.class); //then assertThat(count, is(1L)); assertThat(entityList, is(notNullValue())); assertThat(entityList.size(), is(1)); - assertThat(entityList.get(0).getEmail(), is(settingEntity1.getEmail())); + assertThat(entityList.get(0).getEmail(), is(dynamicSettingAndMappingEntity1.getEmail())); } @Test @@ -115,7 +115,7 @@ public class SettingEntityRepositoryTest { //given //delete , create and apply mapping in before method //when - Map mapping = elasticsearchTemplate.getMapping(SettingEntity.class); + Map mapping = elasticsearchTemplate.getMapping(DynamicSettingAndMappingEntity.class); //then Map properties = (Map) mapping.get("properties"); assertThat(mapping, is(notNullValue())); @@ -127,9 +127,9 @@ public class SettingEntityRepositoryTest { @Test public void shouldCreateMappingWithSpecifiedMappings() { //given - elasticsearchTemplate.deleteIndex(SettingEntity.class); - elasticsearchTemplate.createIndex(SettingEntity.class); - elasticsearchTemplate.refresh(SettingEntity.class, true); + elasticsearchTemplate.deleteIndex(DynamicSettingAndMappingEntity.class); + elasticsearchTemplate.createIndex(DynamicSettingAndMappingEntity.class); + elasticsearchTemplate.refresh(DynamicSettingAndMappingEntity.class, true); //when String mappings = "{\n" + " \"test-setting-type\" : {\n" + @@ -138,10 +138,26 @@ public class SettingEntityRepositoryTest { " }\n" + " }\n" + "}"; - elasticsearchTemplate.putMapping(SettingEntity.class, mappings); - elasticsearchTemplate.refresh(SettingEntity.class, true); + elasticsearchTemplate.putMapping(DynamicSettingAndMappingEntity.class, mappings); + elasticsearchTemplate.refresh(DynamicSettingAndMappingEntity.class, true); //then - Map mapping = elasticsearchTemplate.getMapping(SettingEntity.class); + Map mapping = elasticsearchTemplate.getMapping(DynamicSettingAndMappingEntity.class); + Map properties = (Map) mapping.get("properties"); + assertThat(mapping, is(notNullValue())); + assertThat(properties, is(notNullValue())); + assertThat(((String) ((Map) properties.get("email")).get("type")), is("string")); + assertThat((String) ((Map)properties.get("email")).get("analyzer"), is("emailAnalyzer")); + } + + /* + DATAES-86 + */ + @Test + public void shouldCreateMappingWithUsingMappingAnnotation() { + //given + + //then + Map mapping = elasticsearchTemplate.getMapping(DynamicSettingAndMappingEntity.class); Map properties = (Map) mapping.get("properties"); assertThat(mapping, is(notNullValue())); assertThat(properties, is(notNullValue())); diff --git a/src/test/resources/mappings/test-mappings.json b/src/test/resources/mappings/test-mappings.json new file mode 100644 index 000000000..07ba4c87e --- /dev/null +++ b/src/test/resources/mappings/test-mappings.json @@ -0,0 +1,7 @@ +{ + "test-setting-type" : { + "properties" : { + "email" : {"type" : "string", "analyzer" : "emailAnalyzer" } + } + } +}