From ef1dca31e4a137b1338b02f66af92f147aea52bf Mon Sep 17 00:00:00 2001 From: Chris White Date: Wed, 21 Dec 2016 16:36:38 -0800 Subject: [PATCH] DATAES-198 - Fixed @Version annotation on fields. --- .../core/DefaultResultMapper.java | 21 ++++++ .../core/ElasticsearchTemplate.java | 10 ++- .../core/DefaultResultMapperTests.java | 69 +++++++++++++++++++ .../core/ElasticsearchTemplateTests.java | 9 ++- .../elasticsearch/entities/SampleEntity.java | 3 + 5 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java index d75e4535c..0c334b5d9 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java @@ -39,6 +39,7 @@ import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPa import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.util.Assert; import com.fasterxml.jackson.core.JsonEncoding; import com.fasterxml.jackson.core.JsonFactory; @@ -49,6 +50,7 @@ import com.fasterxml.jackson.core.JsonGenerator; * @author Petar Tahchiev * @author Young Gu * @author Oliver Gierke + * @author Chris White * @author Mark Paluch * @author Ilkang Na */ @@ -89,6 +91,7 @@ public class DefaultResultMapper extends AbstractResultMapper { result = mapEntity(hit.getFields().values(), clazz); } setPersistentEntityId(result, hit.getId(), clazz); + setPersistentEntityVersion(result, hit.getVersion(), clazz); populateScriptFields(result, hit); results.add(result); } @@ -154,6 +157,7 @@ public class DefaultResultMapper extends AbstractResultMapper { T result = mapEntity(response.getSourceAsString(), clazz); if (result != null) { setPersistentEntityId(result, response.getId(), clazz); + setPersistentEntityVersion(result, response.getVersion(), clazz); } return result; } @@ -165,6 +169,7 @@ public class DefaultResultMapper extends AbstractResultMapper { if (!response.isFailed() && response.getResponse().isExists()) { T result = mapEntity(response.getResponse().getSourceAsString(), clazz); setPersistentEntityId(result, response.getResponse().getId(), clazz); + setPersistentEntityVersion(result, response.getResponse().getVersion(), clazz); list.add(result); } } @@ -185,4 +190,20 @@ public class DefaultResultMapper extends AbstractResultMapper { } } + + private void setPersistentEntityVersion(T result, long version, Class clazz) { + if (mappingContext != null && clazz.isAnnotationPresent(Document.class)) { + + ElasticsearchPersistentEntity persistentEntity = mappingContext.getPersistentEntity(clazz); + ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty(); + + // Only deal with Long because ES versions are longs ! + if (versionProperty != null && versionProperty.getType().isAssignableFrom(Long.class)) { + // check that a version was actually returned in the response, -1 would indicate that + // a search didn't request the version ids in the response, which would be an issue + Assert.isTrue(version != -1, "Version in response is -1"); + persistentEntity.getPropertyAccessor(result).setProperty(versionProperty, version); + } + } + } } 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 9895ce7ee..2d37fdc67 100755 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -106,6 +106,7 @@ import org.springframework.util.Assert; * @author Young Gu * @author Oliver Gierke * @author Mark Janssen + * @author Chris White * @author Mark Paluch * @author Ilkang Na * @author Alen Turkovic @@ -733,7 +734,10 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati private SearchRequestBuilder prepareScroll(Query query, long scrollTimeInMillis) { SearchRequestBuilder requestBuilder = client.prepareSearch(toArray(query.getIndices())) - .setTypes(toArray(query.getTypes())).setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).setFrom(0); + .setTypes(toArray(query.getTypes())) + .setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)) + .setFrom(0) + .setVersion(true); if(query.getPageable().isPaged()){ requestBuilder.setSize(query.getPageable().getPageSize()); @@ -979,7 +983,9 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati int startRecord = 0; SearchRequestBuilder searchRequestBuilder = client.prepareSearch(toArray(query.getIndices())) - .setSearchType(query.getSearchType()).setTypes(toArray(query.getTypes())); + .setSearchType(query.getSearchType()) + .setTypes(toArray(query.getTypes())) + .setVersion(true); if (query.getSourceFilter() != null) { SourceFilter sourceFilter = query.getSourceFilter(); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java b/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java index 9a525ea8a..a33270561 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java @@ -15,13 +15,17 @@ */ package org.springframework.data.elasticsearch.core; +import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; import java.util.Map; import com.fasterxml.jackson.databind.util.ArrayIterator; import lombok.Getter; import lombok.NoArgsConstructor; import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.get.MultiGetItemResponse; +import org.elasticsearch.action.get.MultiGetResponse; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.document.DocumentField; import org.elasticsearch.search.SearchHit; @@ -39,6 +43,7 @@ import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; import org.springframework.data.elasticsearch.entities.Car; +import org.springframework.data.elasticsearch.entities.SampleEntity; import static java.util.Arrays.asList; import static org.hamcrest.Matchers.*; @@ -48,6 +53,7 @@ import static org.mockito.Mockito.*; /** * @author Artur Konczak * @author Mohsin Husen + * @author Chris White * @author Mark Paluch * @author Ilkang Na */ @@ -152,6 +158,69 @@ public class DefaultResultMapperTests { assertThat(result.getId(), is("identifier")); } + @Test // DATAES-198 + public void setsVersionFromGetResponse() { + GetResponse response = mock(GetResponse.class); + when(response.getSourceAsString()).thenReturn("{}"); + when(response.getVersion()).thenReturn(1234L); + + SampleEntity result = resultMapper.mapResult(response, SampleEntity.class); + + assertThat(result, is(notNullValue())); + assertThat(result.getVersion(), is(1234L)); + } + + @Test // DATAES-198 + public void setsVersionFromMultiGetResponse() { + GetResponse response1 = mock(GetResponse.class); + when(response1.getSourceAsString()).thenReturn("{}"); + when(response1.isExists()).thenReturn(true); + when(response1.getVersion()).thenReturn(1234L); + + GetResponse response2 = mock(GetResponse.class); + when(response2.getSourceAsString()).thenReturn("{}"); + when(response2.isExists()).thenReturn(true); + when(response2.getVersion()).thenReturn(5678L); + + MultiGetResponse multiResponse = mock(MultiGetResponse.class); + when(multiResponse.getResponses()).thenReturn(new MultiGetItemResponse[] { + new MultiGetItemResponse(response1, null), new MultiGetItemResponse(response2, null) }); + + LinkedList results = resultMapper.mapResults(multiResponse, SampleEntity.class); + + assertThat(results, is(notNullValue())); + assertThat(results, hasSize(2)); + + assertThat(results.get(0).getVersion(), is(1234L)); + assertThat(results.get(1).getVersion(), is(5678L)); + } + + @Test // DATAES-198 + public void setsVersionFromSearchResponse() { + SearchHit hit1 = mock(SearchHit.class); + when(hit1.getSourceAsString()).thenReturn("{}"); + when(hit1.getVersion()).thenReturn(1234L); + + SearchHit hit2 = mock(SearchHit.class); + when(hit2.getSourceAsString()).thenReturn("{}"); + when(hit2.getVersion()).thenReturn(5678L); + + SearchHits searchHits = mock(SearchHits.class); + when(searchHits.getTotalHits()).thenReturn(2L); + when(searchHits.iterator()).thenReturn(Arrays.asList(hit1, hit2).iterator()); + + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(searchHits); + + AggregatedPage results = resultMapper.mapResults(searchResponse, SampleEntity.class, + mock(Pageable.class)); + + assertThat(results, is(notNullValue())); + + assertThat(results.getContent().get(0).getVersion(), is(1234L)); + assertThat(results.getContent().get(1).getVersion(), is(5678L)); + } + private Aggregation createCarAggregation() { Aggregation aggregation = mock(Terms.class); when(aggregation.getName()).thenReturn("Diesel"); 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 4769096da..facd4f5dd 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -71,6 +71,7 @@ import static org.springframework.data.elasticsearch.utils.IndexBuilder.*; * @author Abdul Mohammed * @author Kevin Leturc * @author Mason Chan + * @author Chris White * @author Ilkang Na * @author Alen Turkovic */ @@ -2017,13 +2018,17 @@ public class ElasticsearchTemplateTests { } private IndexQuery getIndexQuery(SampleEntity sampleEntity) { - return new IndexQueryBuilder().withId(sampleEntity.getId()).withObject(sampleEntity).build(); + return new IndexQueryBuilder() + .withId(sampleEntity.getId()) + .withObject(sampleEntity) + .withVersion(sampleEntity.getVersion()) + .build(); } private List getIndexQueries(List sampleEntities) { List indexQueries = new ArrayList<>(); for (SampleEntity sampleEntity : sampleEntities) { - indexQueries.add(new IndexQueryBuilder().withId(sampleEntity.getId()).withObject(sampleEntity).build()); + indexQueries.add(getIndexQuery(sampleEntity)); } return indexQueries; } diff --git a/src/test/java/org/springframework/data/elasticsearch/entities/SampleEntity.java b/src/test/java/org/springframework/data/elasticsearch/entities/SampleEntity.java index b0147b639..b931346c9 100644 --- a/src/test/java/org/springframework/data/elasticsearch/entities/SampleEntity.java +++ b/src/test/java/org/springframework/data/elasticsearch/entities/SampleEntity.java @@ -23,6 +23,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.ToString; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Version; import org.springframework.data.elasticsearch.annotations.Document; @@ -34,12 +35,14 @@ import static org.springframework.data.elasticsearch.annotations.FieldType.*; /** * @author Rizwan Idrees * @author Mohsin Husen + * @author Chris White */ @Setter @Getter @NoArgsConstructor @AllArgsConstructor +@ToString @Builder @Document(indexName = "test-index-sample", type = "test-type", shards = 1, replicas = 0, refreshInterval = "-1") public class SampleEntity {