diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultEntityMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultEntityMapper.java index 1a05ab4b1..1806c59e5 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultEntityMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultEntityMapper.java @@ -17,11 +17,11 @@ package org.springframework.data.elasticsearch.core; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.springframework.data.annotation.ReadOnlyProperty; +import org.springframework.data.elasticsearch.Document; import org.springframework.data.elasticsearch.core.geo.CustomGeoModule; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; @@ -44,6 +44,7 @@ import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; * @author Petar Tahchiev * @author Oliver Gierke * @author Christoph Strobl + * @author Mark Paluch */ public class DefaultEntityMapper implements EntityMapper { @@ -51,7 +52,7 @@ public class DefaultEntityMapper implements EntityMapper { /** * Creates a new {@link DefaultEntityMapper} using the given {@link MappingContext}. - * + * * @param context must not be {@literal null}. */ public DefaultEntityMapper( @@ -74,7 +75,8 @@ public class DefaultEntityMapper implements EntityMapper { */ @Override public String mapToString(Object object) throws IOException { - return objectMapper.writeValueAsString(object); + return objectMapper + .writeValueAsString(object instanceof Document ? new LinkedHashMap<>((Document) object) : object); } /* @@ -82,10 +84,10 @@ public class DefaultEntityMapper implements EntityMapper { * @see org.springframework.data.elasticsearch.core.EntityMapper#mapObject(java.lang.Object) */ @Override - public Map mapObject(Object source) { + public Document mapObject(Object source) { try { - return objectMapper.readValue(mapToString(source), HashMap.class); + return objectMapper.readValue(mapToString(source), Document.class); } catch (IOException e) { throw new MappingException(e.getMessage(), e); } @@ -105,8 +107,7 @@ public class DefaultEntityMapper implements EntityMapper { * @see org.springframework.data.elasticsearch.core.EntityMapper#readObject(java.util.Map, java.lang.Class) */ @Override - public T readObject (Map source, Class targetType) { - + public T readObject(Document source, Class targetType) { try { return mapToObject(mapToString(source), targetType); } catch (IOException e) { @@ -126,7 +127,7 @@ public class DefaultEntityMapper implements EntityMapper { /** * Creates a new {@link SpringDataElasticsearchModule} using the given {@link MappingContext}. - * + * * @param context must not be {@literal null}. */ public SpringDataElasticsearchModule( @@ -156,7 +157,7 @@ public class DefaultEntityMapper implements EntityMapper { this.context = context; } - /* + /* * (non-Javadoc) * @see com.fasterxml.jackson.databind.ser.BeanSerializerModifier#changeProperties(com.fasterxml.jackson.databind.SerializationConfig, com.fasterxml.jackson.databind.BeanDescription, java.util.List) */ 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 762076f7c..576812924 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java @@ -15,11 +15,7 @@ */ package org.springframework.data.elasticsearch.core; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import org.elasticsearch.action.get.GetResponse; @@ -45,11 +41,6 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -import com.fasterxml.jackson.core.JsonEncoding; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; /** * @author Artur Konczak @@ -105,13 +96,7 @@ public class DefaultResultMapper extends AbstractResultMapper { List results = new ArrayList<>(); for (SearchHit hit : response.getHits()) { if (hit != null) { - T result = null; - String hitSourceAsString = hit.getSourceAsString(); - if (!StringUtils.isEmpty(hitSourceAsString)) { - result = mapEntity(hitSourceAsString, clazz); - } else { - result = mapEntity(hit.getFields().values(), clazz); - } + T result = mapSearchHit(hit, clazz); setPersistentEntityId(result, hit.getId(), clazz); setPersistentEntityVersion(result, hit.getVersion(), clazz); @@ -149,38 +134,14 @@ public class DefaultResultMapper extends AbstractResultMapper { } } - private T mapEntity(Collection values, Class clazz) { - return mapEntity(buildJSONFromFields(values), clazz); - } - - private String buildJSONFromFields(Collection values) { - JsonFactory nodeFactory = new JsonFactory(); - try { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - JsonGenerator generator = nodeFactory.createGenerator(stream, JsonEncoding.UTF8); - generator.writeStartObject(); - for (DocumentField value : values) { - if (value.getValues().size() > 1) { - generator.writeArrayFieldStart(value.getName()); - for (Object val : value.getValues()) { - generator.writeObject(val); - } - generator.writeEndArray(); - } else { - generator.writeObjectField(value.getName(), value.getValue()); - } - } - generator.writeEndObject(); - generator.flush(); - return new String(stream.toByteArray(), Charset.forName("UTF-8")); - } catch (IOException e) { - return null; - } - } - @Override public T mapResult(GetResponse response, Class clazz) { - T result = mapEntity(response.getSourceAsString(), clazz); + + if (!response.isExists()) { + return null; + } + + T result = mapDocument(DocumentAdapters.from(response), clazz); if (result != null) { setPersistentEntityId(result, response.getId(), clazz); setPersistentEntityVersion(result, response.getVersion(), clazz); @@ -193,7 +154,7 @@ public class DefaultResultMapper extends AbstractResultMapper { List list = new ArrayList<>(); for (MultiGetItemResponse response : responses.getResponses()) { if (!response.isFailed() && response.getResponse().isExists()) { - T result = mapEntity(response.getResponse().getSourceAsString(), clazz); + T result = mapResult(response.getResponse(), clazz); setPersistentEntityId(result, response.getResponse().getId(), clazz); setPersistentEntityVersion(result, response.getResponse().getVersion(), clazz); list.add(result); diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapper.java index 49db1e0d7..924dd6adb 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapper.java @@ -15,8 +15,6 @@ */ package org.springframework.data.elasticsearch.core; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.ObjectWriter; import lombok.RequiredArgsConstructor; import java.io.IOException; @@ -34,6 +32,8 @@ import org.springframework.data.convert.EntityInstantiator; import org.springframework.data.convert.EntityInstantiators; import org.springframework.data.convert.EntityReader; import org.springframework.data.convert.EntityWriter; +import org.springframework.data.elasticsearch.Document; +import org.springframework.data.elasticsearch.SearchDocument; import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions; import org.springframework.data.elasticsearch.core.convert.ElasticsearchTypeMapper; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; @@ -52,6 +52,8 @@ import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.ObjectWriter; /** * Elasticsearch specific {@link EntityReader} & {@link EntityWriter} implementation based on domain type @@ -59,12 +61,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; * * @author Christoph Strobl * @author Peter-Josef Meisch + * @author Mark Paluch * @since 3.2 */ -public class ElasticsearchEntityMapper implements - EntityConverter, ElasticsearchPersistentProperty, Object, Map>, - EntityWriter>, EntityReader>, InitializingBean, - EntityMapper { +public class ElasticsearchEntityMapper + implements EntityConverter, ElasticsearchPersistentProperty, Object, Document>, + EntityWriter, EntityReader, InitializingBean, EntityMapper { private final MappingContext, ElasticsearchPersistentProperty> mappingContext; private final GenericConversionService conversionService; @@ -134,14 +136,14 @@ public class ElasticsearchEntityMapper implements // --> READ @Override - public T readObject(Map source, Class targetType) { + public T readObject(Document source, Class targetType) { return read(targetType, source); } @SuppressWarnings("unchecked") @Override @Nullable - public R read(Class type, Map source) { + public R read(Class type, Document source) { return doRead(source, ClassTypeInformation.from((Class) ClassUtils.getUserClass(type))); } @@ -320,16 +322,16 @@ public class ElasticsearchEntityMapper implements // --> WRITE @Override - public Map mapObject(Object source) { + public Document mapObject(Object source) { - LinkedHashMap target = new LinkedHashMap<>(); + Document target = Document.create(); write(source, target); return target; } @SuppressWarnings("unchecked") @Override - public void write(@Nullable Object source, Map sink) { + public void write(@Nullable Object source, Document sink) { if (source == null) { return; @@ -351,8 +353,7 @@ public class ElasticsearchEntityMapper implements doWrite(source, sink, type); } - protected void doWrite(@Nullable Object source, Map sink, - @Nullable TypeInformation typeHint) { + protected void doWrite(@Nullable Object source, Document sink, @Nullable TypeInformation typeHint) { if (source == null) { return; @@ -382,7 +383,7 @@ public class ElasticsearchEntityMapper implements writeEntity(entity, source, sink, null); } - protected void writeEntity(ElasticsearchPersistentEntity entity, Object source, Map sink, + protected void writeEntity(ElasticsearchPersistentEntity entity, Object source, Document sink, @Nullable TypeInformation containingStructure) { PersistentPropertyAccessor accessor = entity.getPropertyAccessor(source); @@ -391,11 +392,11 @@ public class ElasticsearchEntityMapper implements typeMapper.writeType(source.getClass(), sink); } - writeProperties(entity, accessor, sink); + writeProperties(entity, accessor, new MapValueAccessor(sink)); } protected void writeProperties(ElasticsearchPersistentEntity entity, PersistentPropertyAccessor accessor, - Map sink) { + MapValueAccessor sink) { for (ElasticsearchPersistentProperty property : entity) { @@ -412,19 +413,19 @@ public class ElasticsearchEntityMapper implements if (!isSimpleType(value)) { writeProperty(property, value, sink); } else { - sink.put(property.getFieldName(), getWriteSimpleValue(value)); + sink.set(property, getWriteSimpleValue(value)); } } } - protected void writeProperty(ElasticsearchPersistentProperty property, Object value, Map sink) { + protected void writeProperty(ElasticsearchPersistentProperty property, Object value, MapValueAccessor sink) { Optional> customWriteTarget = conversions.getCustomWriteTarget(value.getClass()); if (customWriteTarget.isPresent()) { Class writeTarget = customWriteTarget.get(); - sink.put(property.getFieldName(), conversionService.convert(value, writeTarget)); + sink.set(property, conversionService.convert(value, writeTarget)); return; } @@ -442,7 +443,7 @@ public class ElasticsearchEntityMapper implements } } - sink.put(property.getFieldName(), getWriteComplexValue(property, typeHint, value)); + sink.set(property, getWriteComplexValue(property, typeHint, value)); } protected Object getWriteSimpleValue(Object value) { @@ -479,7 +480,8 @@ public class ElasticsearchEntityMapper implements } private Object writeEntity(Object value, ElasticsearchPersistentProperty property, TypeInformation typeHint) { - Map target = new LinkedHashMap<>(); + + Document target = Document.create(); writeEntity(mappingContext.getRequiredPersistentEntity(value.getClass()), value, target, property.getTypeInformation()); return target; @@ -549,15 +551,15 @@ public class ElasticsearchEntityMapper implements @Override public String mapToString(Object source) throws IOException { - Map sink = new LinkedHashMap<>(); + Document sink = Document.create(); write(source, sink); - return objectWriter.writeValueAsString(sink); + return objectWriter.writeValueAsString(new LinkedHashMap<>(sink)); } @Override public T mapToObject(String source, Class clazz) throws IOException { - return read(clazz, objectReader.readValue(source)); + return read(clazz, Document.from(objectReader.readValue(source))); } // --> PRIVATE HELPERS @@ -669,6 +671,18 @@ public class ElasticsearchEntityMapper implements public Object get(ElasticsearchPersistentProperty property) { + if (property.isIdProperty() && ((Document) target).hasId()) { + return ((Document) target).getId(); + } + + if (property.isVersionProperty() && ((Document) target).hasVersion()) { + return ((Document) target).getVersion(); + } + + if (property.isScoreProperty()) { + return ((SearchDocument) target).getScore(); + } + String fieldName = property.getFieldName(); if (!fieldName.contains(".")) { @@ -691,6 +705,19 @@ public class ElasticsearchEntityMapper implements return result; } + public void set(ElasticsearchPersistentProperty property, Object value) { + + if (property.isIdProperty()) { + ((Document) target).setId((String) value); + } + + if (property.isVersionProperty()) { + ((Document) target).setVersion((Long) value); + } + + target.put(property.getFieldName(), value); + } + @SuppressWarnings("unchecked") private Map getAsMap(Object result) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/EntityMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/EntityMapper.java index 1be69b912..f94dd705b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/EntityMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/EntityMapper.java @@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core; import java.io.IOException; import java.util.Map; +import org.springframework.data.elasticsearch.Document; import org.springframework.lang.Nullable; /** @@ -27,6 +28,7 @@ import org.springframework.lang.Nullable; * @author Rizwan Idrees * @author Mohsin Husen * @author Christoph Strobl + * @author Mark Paluch */ public interface EntityMapper { @@ -41,7 +43,7 @@ public interface EntityMapper { * @return never {@literal null} * @since 3.2 */ - Map mapObject(Object source); + Document mapObject(Object source); /** * Map the given {@link Map} into an instance of the {@literal targetType}. @@ -53,5 +55,5 @@ public interface EntityMapper { * @since 3.2 */ @Nullable - T readObject(Map source, Class targetType); + T readObject(Document source, Class targetType); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ResultsMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/ResultsMapper.java index 41c8b1480..59b0492ba 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ResultsMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ResultsMapper.java @@ -16,10 +16,11 @@ package org.springframework.data.elasticsearch.core; import java.io.IOException; -import java.util.Map; import org.elasticsearch.index.get.GetResult; import org.elasticsearch.search.SearchHit; + +import org.springframework.data.elasticsearch.Document; import org.springframework.data.elasticsearch.ElasticsearchException; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; @@ -34,6 +35,7 @@ import org.springframework.util.StringUtils; * @author Mohsin Husen * @author Artur Konczak * @author Christoph Strobl + * @author Mark Paluch */ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, MultiGetResultMapper { @@ -50,6 +52,7 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult } @Nullable + @Deprecated default T mapEntity(String source, Class clazz) { if (StringUtils.isEmpty(source)) { @@ -63,27 +66,18 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult } /** - * Map a single {@link GetResult} to an instance of the given type. + * Map a single {@link Document} to an instance of the given type. * - * @param getResult must not be {@literal null}. + * @param document must not be {@literal null}. * @param type must not be {@literal null}. * @param - * @return can be {@literal null} if the {@link GetResult#isSourceEmpty() is empty}. - * @since 3.2 + * @return can be {@literal null} if the {@link Document#isEmpty() is empty}. + * @since 4.0 */ @Nullable - default T mapGetResult(GetResult getResult, Class type) { + default T mapDocument(Document document, Class type) { - if (getResult.isSourceEmpty()) { - return null; - } - - Map source = getResult.getSource(); - if (!source.containsKey("id") || source.get("id") == null) { - source.put("id", getResult.getId()); - } - - Object mappedResult = getEntityMapper().readObject(source, type); + Object mappedResult = getEntityMapper().readObject(document, type); if (mappedResult == null) { return (T) null; @@ -96,6 +90,20 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult return type.cast(mappedResult); } + /** + * Map a single {@link GetResult} to an instance of the given type. + * + * @param getResult must not be {@literal null}. + * @param type must not be {@literal null}. + * @param + * @return can be {@literal null} if the {@link GetResult#isSourceEmpty() is empty}. + * @since 3.2 + */ + @Nullable + default T mapGetResult(GetResult getResult, Class type) { + return mapDocument(DocumentAdapters.from(getResult), type); + } + /** * Map a single {@link SearchHit} to an instance of the given type. * @@ -107,26 +115,6 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult */ @Nullable default T mapSearchHit(SearchHit searchHit, Class type) { - - if (!searchHit.hasSource()) { - return null; - } - - Map source = searchHit.getSourceAsMap(); - if (!source.containsKey("id") || source.get("id") == null) { - source.put("id", searchHit.getId()); - } - - Object mappedResult = getEntityMapper().readObject(source, type); - - if (mappedResult == null) { - return null; - } - - if (type.isInterface()) { - return getProjectionFactory().createProjection(type, mappedResult); - } - - return type.cast(mappedResult); + return mapDocument(DocumentAdapters.from(searchHit), type); } } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/CustomEntityMapper.java b/src/test/java/org/springframework/data/elasticsearch/core/CustomEntityMapper.java index 4869028d4..1db5057bf 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/CustomEntityMapper.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/CustomEntityMapper.java @@ -16,11 +16,13 @@ package org.springframework.data.elasticsearch.core; import java.io.IOException; -import java.util.Map; + +import org.springframework.data.elasticsearch.Document; /** * @author Artur Konczak * @author Mohsin Husen + * @author Mark Paluch */ public class CustomEntityMapper implements EntityMapper { @@ -41,12 +43,12 @@ public class CustomEntityMapper implements EntityMapper { } @Override - public Map mapObject(Object source) { + public Document mapObject(Object source) { return null; } @Override - public T readObject(Map source, Class targetType) { + public T readObject(Document source, Class targetType) { return null; } } 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 78ad6aa2c..90f83c0d1 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java @@ -30,6 +30,7 @@ import java.lang.Object; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -38,6 +39,7 @@ 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.bytes.BytesArray; import org.elasticsearch.common.document.DocumentField; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; @@ -172,7 +174,14 @@ public class DefaultResultMapperTests { // given GetResponse response = mock(GetResponse.class); - when(response.getSourceAsString()).thenReturn(createJsonCar("Ford", "Grat")); + when(response.isExists()).thenReturn(true); + + Map sourceAsMap = new HashMap<>(); + sourceAsMap.put("name", "Ford"); + sourceAsMap.put("model", "Grat"); + + when(response.getSourceAsMap()).thenReturn(sourceAsMap); + when(response.getSourceAsBytesRef()).thenReturn(new BytesArray(" ")); // when Car result = resultMapper.mapResult(response, Car.class); @@ -188,7 +197,9 @@ public class DefaultResultMapperTests { public void setsIdentifierOnImmutableType() { GetResponse response = mock(GetResponse.class); + when(response.isExists()).thenReturn(true); when(response.getSourceAsString()).thenReturn("{}"); + when(response.getSourceAsBytesRef()).thenReturn(new BytesArray("{}")); when(response.getId()).thenReturn("identifier"); ImmutableEntity result = resultMapper.mapResult(response, ImmutableEntity.class); @@ -201,6 +212,7 @@ public class DefaultResultMapperTests { public void setsVersionFromGetResponse() { GetResponse response = mock(GetResponse.class); + when(response.isExists()).thenReturn(true); when(response.getSourceAsString()).thenReturn("{}"); when(response.getVersion()).thenReturn(1234L); @@ -214,12 +226,16 @@ public class DefaultResultMapperTests { public void setsVersionFromMultiGetResponse() { GetResponse response1 = mock(GetResponse.class); + when(response1.isExists()).thenReturn(true); when(response1.getSourceAsString()).thenReturn("{}"); + when(response1.getSourceAsBytesRef()).thenReturn(new BytesArray("{}")); when(response1.isExists()).thenReturn(true); when(response1.getVersion()).thenReturn(1234L); GetResponse response2 = mock(GetResponse.class); + when(response2.isExists()).thenReturn(true); when(response2.getSourceAsString()).thenReturn("{}"); + when(response2.getSourceAsBytesRef()).thenReturn(new BytesArray("{}")); when(response2.isExists()).thenReturn(true); when(response2.getVersion()).thenReturn(5678L); @@ -239,11 +255,11 @@ public class DefaultResultMapperTests { public void setsVersionFromSearchResponse() { SearchHit hit1 = mock(SearchHit.class); - when(hit1.getSourceAsString()).thenReturn("{}"); + when(hit1.getSourceRef()).thenReturn(new BytesArray("{}")); when(hit1.getVersion()).thenReturn(1234L); SearchHit hit2 = mock(SearchHit.class); - when(hit2.getSourceAsString()).thenReturn("{}"); + when(hit2.getSourceRef()).thenReturn(new BytesArray("{}")); when(hit2.getVersion()).thenReturn(5678L); SearchHits searchHits = mock(SearchHits.class); @@ -272,7 +288,13 @@ public class DefaultResultMapperTests { private SearchHit createCarHit(String name, String model) { SearchHit hit = mock(SearchHit.class); - when(hit.getSourceAsString()).thenReturn(createJsonCar(name, model)); + String json = createJsonCar(name, model); + when(hit.getSourceAsString()).thenReturn(json); + when(hit.getSourceRef()).thenReturn(new BytesArray(json)); + Map map = new LinkedHashMap<>(); + map.put("name", name); + map.put("model", model); + when(hit.getSourceAsMap()).thenReturn(map); return hit; } @@ -281,6 +303,7 @@ public class DefaultResultMapperTests { SearchHit hit = mock(SearchHit.class); when(hit.getSourceAsString()).thenReturn(null); when(hit.getFields()).thenReturn(createCarFields(name, model)); + when(hit.iterator()).thenReturn(createCarFields(name, model).values().iterator()); return hit; } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapperUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapperUnitTests.java index a7d1fb4c1..201517c23 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapperUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapperUnitTests.java @@ -47,7 +47,7 @@ import org.springframework.data.annotation.Transient; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; -import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.Document; import org.springframework.data.elasticsearch.annotations.GeoPointField; import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions; import org.springframework.data.elasticsearch.core.geo.GeoPoint; @@ -58,7 +58,10 @@ import org.springframework.data.geo.Point; import org.springframework.data.geo.Polygon; /** + * Unit tests for {@link ElasticsearchEntityMapper}. + * * @author Christoph Strobl + * @author Mark Paluch */ public class ElasticsearchEntityMapperUnitTests { @@ -79,16 +82,16 @@ public class ElasticsearchEntityMapperUnitTests { Address observatoryRoad; Place bigBunsCafe; - Map sarahAsMap; - Map t800AsMap; - Map kyleAsMap; - Map gratiotAveAsMap; - Map locationAsMap; - Map gunAsMap; - Map grenadeAsMap; - Map rifleAsMap; - Map shotGunAsMap; - Map bigBunsCafeAsMap; + Document sarahAsMap; + Document t800AsMap; + Document kyleAsMap; + Document gratiotAveAsMap; + Document locationAsMap; + Document gunAsMap; + Document grenadeAsMap; + Document rifleAsMap; + Document shotGunAsMap; + Document bigBunsCafeAsMap; @Before public void init() { @@ -117,7 +120,7 @@ public class ElasticsearchEntityMapperUnitTests { t800.name = "T-800"; t800.gender = Gender.MACHINE; - t800AsMap = new LinkedHashMap<>(); + t800AsMap = Document.create(); t800AsMap.put("id", "t800"); t800AsMap.put("name", "T-800"); t800AsMap.put("gender", "MACHINE"); @@ -134,27 +137,27 @@ public class ElasticsearchEntityMapperUnitTests { bigBunsCafe.street = "15 South Fremont Avenue"; bigBunsCafe.location = new Point(34.0945637D, -118.1545845D); - sarahAsMap = new LinkedHashMap<>(); + sarahAsMap = Document.create(); sarahAsMap.put("id", "sarah"); sarahAsMap.put("name", "Sarah Connor"); sarahAsMap.put("gender", "MAN"); sarahAsMap.put("_class", "org.springframework.data.elasticsearch.core.ElasticsearchEntityMapperUnitTests$Person"); - kyleAsMap = new LinkedHashMap<>(); + kyleAsMap = Document.create(); kyleAsMap.put("id", "kyle"); kyleAsMap.put("gender", "MAN"); kyleAsMap.put("name", "Kyle Reese"); - locationAsMap = new LinkedHashMap<>(); + locationAsMap = Document.create(); locationAsMap.put("lat", 34.118347D); locationAsMap.put("lon", -118.3026284D); - gratiotAveAsMap = new LinkedHashMap<>(); + gratiotAveAsMap = Document.create(); gratiotAveAsMap.put("city", "Los Angeles"); gratiotAveAsMap.put("street", "2800 East Observatory Road"); gratiotAveAsMap.put("location", locationAsMap); - bigBunsCafeAsMap = new LinkedHashMap<>(); + bigBunsCafeAsMap = Document.create(); bigBunsCafeAsMap.put("name", "Big Buns Cafe"); bigBunsCafeAsMap.put("city", "Los Angeles"); bigBunsCafeAsMap.put("street", "15 South Fremont Avenue"); @@ -164,22 +167,22 @@ public class ElasticsearchEntityMapperUnitTests { bigBunsCafeAsMap.put("_class", "org.springframework.data.elasticsearch.core.ElasticsearchEntityMapperUnitTests$Place"); - gunAsMap = new LinkedHashMap<>(); + gunAsMap = Document.create(); gunAsMap.put("label", "Glock 19"); gunAsMap.put("shotsPerMagazine", 33); gunAsMap.put("_class", Gun.class.getName()); - grenadeAsMap = new LinkedHashMap<>(); + grenadeAsMap = Document.create(); grenadeAsMap.put("label", "40 mm"); grenadeAsMap.put("_class", Grenade.class.getName()); - rifleAsMap = new LinkedHashMap<>(); + rifleAsMap = Document.create(); rifleAsMap.put("label", "AR-18 Assault Rifle"); rifleAsMap.put("weight", 3.17D); rifleAsMap.put("maxShotsPerMagazine", 40); rifleAsMap.put("_class", "rifle"); - shotGunAsMap = new LinkedHashMap<>(); + shotGunAsMap = Document.create(); shotGunAsMap.put("model", "Ithaca 37 Pump Shotgun"); shotGunAsMap.put("_class", ShotGun.class.getName()); } @@ -255,7 +258,7 @@ public class ElasticsearchEntityMapperUnitTests { person.gender = Gender.MAN; person.address = observatoryRoad; - LinkedHashMap sink = writeToMap(person); + Map sink = writeToMap(person); assertThat(sink.get("address")).isEqualTo(gratiotAveAsMap); } @@ -269,7 +272,7 @@ public class ElasticsearchEntityMapperUnitTests { sarahConnor.coWorkers = Arrays.asList(kyleReese, ginger); - LinkedHashMap target = writeToMap(sarahConnor); + Map target = writeToMap(sarahConnor); assertThat((List) target.get("coWorkers")).hasSize(2).contains(kyleAsMap); } @@ -281,7 +284,7 @@ public class ElasticsearchEntityMapperUnitTests { sarahConnor.inventoryList = Arrays.asList(gun, grenade); - LinkedHashMap target = writeToMap(sarahConnor); + Map target = writeToMap(sarahConnor); assertThat((List) target.get("inventoryList")).containsExactly(gunAsMap, grenadeAsMap); } @@ -319,7 +322,7 @@ public class ElasticsearchEntityMapperUnitTests { sarahConnor.shippingAddresses = new LinkedHashMap<>(); sarahConnor.shippingAddresses.put("home", observatoryRoad); - LinkedHashMap target = writeToMap(sarahConnor); + Map target = writeToMap(sarahConnor); assertThat(target.get("shippingAddresses")).isInstanceOf(Map.class); assertThat(target.get("shippingAddresses")).isEqualTo(Collections.singletonMap("home", gratiotAveAsMap)); } @@ -331,7 +334,7 @@ public class ElasticsearchEntityMapperUnitTests { sarahConnor.inventoryMap.put("glock19", gun); sarahConnor.inventoryMap.put("40 mm grenade", grenade); - LinkedHashMap target = writeToMap(sarahConnor); + Map target = writeToMap(sarahConnor); assertThat(target.get("inventoryMap")).isInstanceOf(Map.class); assertThat((Map) target.get("inventoryMap")).containsEntry("glock19", gunAsMap).containsEntry("40 mm grenade", grenadeAsMap); @@ -365,7 +368,7 @@ public class ElasticsearchEntityMapperUnitTests { skynet.objectList.add(t800); skynet.objectList.add(gun); - LinkedHashMap target = writeToMap(skynet); + Map target = writeToMap(skynet); assertThat((List) target.get("objectList")).containsExactly(t800AsMap, gunAsMap); } @@ -373,7 +376,7 @@ public class ElasticsearchEntityMapperUnitTests { @Test // DATAES-530 public void readGenericList() { - LinkedHashMap source = new LinkedHashMap<>(); + Document source = Document.create(); source.put("objectList", Arrays.asList(t800AsMap, gunAsMap)); Skynet target = entityMapper.read(Skynet.class, source); @@ -388,7 +391,7 @@ public class ElasticsearchEntityMapperUnitTests { skynet.objectList = new ArrayList<>(); skynet.objectList.add(Arrays.asList(t800, gun)); - LinkedHashMap target = writeToMap(skynet); + Map target = writeToMap(skynet); assertThat((List) target.get("objectList")).containsExactly(Arrays.asList(t800AsMap, gunAsMap)); } @@ -396,7 +399,7 @@ public class ElasticsearchEntityMapperUnitTests { @Test // DATAES-530 public void readGenericListList() { - LinkedHashMap source = new LinkedHashMap<>(); + Document source = Document.create(); source.put("objectList", Arrays.asList(Arrays.asList(t800AsMap, gunAsMap))); Skynet target = entityMapper.read(Skynet.class, source); @@ -412,7 +415,7 @@ public class ElasticsearchEntityMapperUnitTests { skynet.objectMap.put("gun", gun); skynet.objectMap.put("grenade", grenade); - LinkedHashMap target = writeToMap(skynet); + Map target = writeToMap(skynet); assertThat((Map) target.get("objectMap")).containsEntry("gun", gunAsMap).containsEntry("grenade", grenadeAsMap); @@ -421,7 +424,7 @@ public class ElasticsearchEntityMapperUnitTests { @Test // DATAES-530 public void readGenericMap() { - LinkedHashMap source = new LinkedHashMap<>(); + Document source = Document.create(); source.put("objectMap", Collections.singletonMap("glock19", gunAsMap)); Skynet target = entityMapper.read(Skynet.class, source); @@ -436,7 +439,7 @@ public class ElasticsearchEntityMapperUnitTests { skynet.objectMap = new LinkedHashMap<>(); skynet.objectMap.put("inventory", Collections.singletonMap("glock19", gun)); - LinkedHashMap target = writeToMap(skynet); + Map target = writeToMap(skynet); assertThat((Map) target.get("objectMap")).containsEntry("inventory", Collections.singletonMap("glock19", gunAsMap)); @@ -445,7 +448,7 @@ public class ElasticsearchEntityMapperUnitTests { @Test // DATAES-530 public void readGenericMapMap() { - LinkedHashMap source = new LinkedHashMap<>(); + Document source = Document.create(); source.put("objectMap", Collections.singletonMap("inventory", Collections.singletonMap("glock19", gunAsMap))); Skynet target = entityMapper.read(Skynet.class, source); @@ -466,7 +469,7 @@ public class ElasticsearchEntityMapperUnitTests { @Test // DATAES-530 public void readsNestedObjectEntity() { - LinkedHashMap source = new LinkedHashMap<>(); + Document source = Document.create(); source.put("object", t800AsMap); Skynet target = entityMapper.read(Skynet.class, source); @@ -483,7 +486,7 @@ public class ElasticsearchEntityMapperUnitTests { public void writesNestedAliased() { t800.inventoryList = Collections.singletonList(rifle); - LinkedHashMap target = writeToMap(t800); + Map target = writeToMap(t800); assertThat((List) target.get("inventoryList")).contains(rifleAsMap); } @@ -516,7 +519,7 @@ public class ElasticsearchEntityMapperUnitTests { sarahConnor.address = bigBunsCafe; - LinkedHashMap target = writeToMap(sarahConnor); + Map target = writeToMap(sarahConnor); assertThat(target.get("address")).isEqualTo(bigBunsCafeAsMap); } @@ -535,9 +538,9 @@ public class ElasticsearchEntityMapperUnitTests { return String.format(Locale.ENGLISH, "\"%s\":{\"lat\":%.1f,\"lon\":%.1f}", name, point.getX(), point.getY()); } - private LinkedHashMap writeToMap(Object source) { + private Map writeToMap(Object source) { - LinkedHashMap sink = new LinkedHashMap<>(); + Document sink = Document.create(); entityMapper.write(source, sink); return sink; } @@ -696,7 +699,8 @@ public class ElasticsearchEntityMapperUnitTests { @NoArgsConstructor @AllArgsConstructor @Builder - @Document(indexName = "test-index-geo-core-entity-mapper", type = "geo-test-index", shards = 1, replicas = 0, + @org.springframework.data.elasticsearch.annotations.Document(indexName = "test-index-geo-core-entity-mapper", + type = "geo-test-index", shards = 1, replicas = 0, refreshInterval = "-1") static class GeoEntity {