diff --git a/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc b/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc index e98e5471c..e4b399a04 100644 --- a/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc +++ b/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc @@ -66,13 +66,26 @@ for `Converter` registration. <3> Optionally set `CustomConversions` if applicable. ==== +[[elasticsearch.mapping.meta-model.annotations]] +=== Mapping Annotation Overview + +The `ElasticsearchEntityMapper` can use metadata to drive the mapping of objects to documents. The following annotations are available: + +* `@Id`: Applied at the field level to mark the field used for identity purpose. +* `@Document`: Applied at the class level to indicate this class is a candidate for mapping to the database. You can specify the index name and index type where the document will be stored. +* `@Transient`: By default all private fields are mapped to the document, this annotation excludes the field where it is applied from being stored in the database +* `@PersistenceConstructor`: Marks a given constructor - even a package protected one - to use when instantiating the object from the database. Constructor arguments are mapped by name to the key values in the retrieved Document. +* `@Field`: Applied at the field level and described the name of the field as it will be represented in the Elasticsearch document thus allowing the name to be different than the fieldname of the class. + +The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic. + [[elasticsearch.mapping.meta-model.rules]] === Mapping Rules ==== Type Hints -Mapping uses _type hints_ embedded in the document sent to the server to allow generic type mapping. Those type hints are -represented as `_class` attributes within the document on the server and will be written for each aggregate root. +Mapping uses _type hints_ embedded in the document sent to the server to allow generic type mapping. +Those type hints are represented as `_class` attributes within the document and are written for each aggregate root. .Type Hints ==== @@ -123,8 +136,7 @@ public class Person { <1> The configured alias is used when writing the entity. ==== -NOTE: Type hints will not be written for nested Objects unless the properties type is `Object`, an interface or the -actual value type does not match the properties declaration. +NOTE: Type hints will not be written for nested Objects unless the properties type is `Object`, an interface or the actual value type does not match the properties declaration. ==== Geospatial Types @@ -152,8 +164,7 @@ public class Address { ==== Collections -For values inside Collections apply the same mapping rules as for aggregate roots when it comes to _type hints_ -and <>. +For values inside Collections apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <>. .Collections ==== @@ -179,8 +190,7 @@ public class Person { ==== Maps -For values inside Maps apply the same mapping rules as for aggregate roots when it comes to _type hints_ -and <>. +For values inside Maps apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <>. However the Map key needs to a String to be processed by Elasticsearch. .Collections @@ -214,8 +224,7 @@ public class Person { [[elasticsearch.mapping.meta-model.conversions]] === Custom Conversions -Looking at the `Configuration` from the <> `ElasticsearchCustomConversions` -allows to register specific rules for mapping domain and simple types. +Looking at the `Configuration` from the <> `ElasticsearchCustomConversions` allows registering specific rules for mapping domain and simple types. .Meta Model Object Mapping Configuration ==== diff --git a/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java b/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java index d223a838b..9c507611e 100644 --- a/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java +++ b/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java @@ -72,15 +72,14 @@ public class ElasticsearchConfigurationSupport { } /** - * Returns the {@link EntityMapper} used for mapping source <> DomainType.
+ * Returns the {@link EntityMapper} used for mapping between the source and domain type.
* Hint: you can use {@link org.springframework.data.elasticsearch.core.ElasticsearchEntityMapper} as * an alternative to the {@link DefaultEntityMapper}. * - *
{@code
+	 * 
 	 * ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(),
-	 * 			new DefaultConversionService());
+	 * 		new DefaultConversionService());
 	 * entityMapper.setConversions(elasticsearchCustomConversions());
-	 * }
 	 * 
* * @return never {@literal null}. diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractResultMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractResultMapper.java index 7118d9eba..d424dbfa9 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractResultMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractResultMapper.java @@ -28,14 +28,20 @@ public abstract class AbstractResultMapper implements ResultsMapper { private final EntityMapper entityMapper; private final ProjectionFactory projectionFactory; + /** + * Create a new {@link AbstractResultMapper}. + * + * @param entityMapper must not be {@literal null}. + */ public AbstractResultMapper(EntityMapper entityMapper) { this(entityMapper, new SpelAwareProxyProjectionFactory()); } /** + * Create a new {@link AbstractResultMapper}. * - * @param entityMapper - * @param projectionFactory + * @param entityMapper must not be {@literal null}. + * @param projectionFactory must not be {@literal null}. * @since 3.2 */ public AbstractResultMapper(EntityMapper entityMapper, ProjectionFactory projectionFactory) { @@ -47,6 +53,10 @@ public abstract class AbstractResultMapper implements ResultsMapper { this.projectionFactory = projectionFactory; } + /* + * (non-Javadoc) + * @see org.springframework.data.elasticsearch.core.ResultsMapper#getEntityMapper() + */ @Override public EntityMapper getEntityMapper() { return this.entityMapper; @@ -58,6 +68,6 @@ public abstract class AbstractResultMapper implements ResultsMapper { */ @Override public ProjectionFactory getProjectionFactory() { - return projectionFactory; + return this.projectionFactory; } } 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 718eb355f..91543a7d6 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultResultMapper.java @@ -88,12 +88,11 @@ public class DefaultResultMapper extends AbstractResultMapper { this.mappingContext = mappingContext; } - static EntityMapper initEntityMapper( + private static EntityMapper initEntityMapper( MappingContext, ElasticsearchPersistentProperty> mappingContext) { Assert.notNull(mappingContext, "MappingContext must not be null!"); return new DefaultEntityMapper(mappingContext); - } @Override 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 0c076a25f..bd681d866 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchEntityMapper.java @@ -15,6 +15,8 @@ */ package org.springframework.data.elasticsearch.core; +import lombok.RequiredArgsConstructor; + import java.io.IOException; import java.util.*; import java.util.Map.Entry; @@ -34,7 +36,6 @@ import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomCo import org.springframework.data.elasticsearch.core.convert.ElasticsearchTypeMapper; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; -import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.ConvertingPropertyAccessor; @@ -76,7 +77,49 @@ public class ElasticsearchEntityMapper implements this.mappingContext = mappingContext; this.conversionService = conversionService != null ? conversionService : new DefaultConversionService(); - this.typeMapper = ElasticsearchTypeMapper.defaultTypeMapper(mappingContext); + this.typeMapper = ElasticsearchTypeMapper.create(mappingContext); + } + + // --> GETTERS / SETTERS + + @Override + public MappingContext, ElasticsearchPersistentProperty> getMappingContext() { + return mappingContext; + } + + @Override + public ConversionService getConversionService() { + return conversionService; + } + + /** + * Set the {@link CustomConversions} to be applied during the mapping process.
+ * Conversions are registered after {@link #afterPropertiesSet() bean initialization}. + * + * @param conversions must not be {@literal null}. + */ + public void setConversions(CustomConversions conversions) { + this.conversions = conversions; + } + + /** + * Set the {@link ElasticsearchTypeMapper} to use for reading / writing type hints. + * + * @param typeMapper must not be {@literal null}. + */ + public void setTypeMapper(ElasticsearchTypeMapper typeMapper) { + this.typeMapper = typeMapper; + } + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() { + + DateFormatterRegistrar.addDateConverters(conversionService); + conversions.registerConvertersIn(conversionService); } // --> READ @@ -86,12 +129,14 @@ public class ElasticsearchEntityMapper implements return read(targetType, source); } + @SuppressWarnings("unchecked") @Override @Nullable public R read(Class type, Map source) { return doRead(source, ClassTypeInformation.from((Class) ClassUtils.getUserClass(type))); } + @SuppressWarnings("unchecked") @Nullable protected R doRead(Map source, TypeInformation typeHint) { @@ -113,6 +158,7 @@ public class ElasticsearchEntityMapper implements return readEntity(entity, source); } + @SuppressWarnings("unchecked") protected R readEntity(ElasticsearchPersistentEntity entity, Map source) { ElasticsearchPersistentEntity targetEntity = computeClosestEntity(entity, source); @@ -125,11 +171,8 @@ public class ElasticsearchEntityMapper implements R instance = (R) instantiator.createInstance(targetEntity, new PersistentEntityParameterValueProvider<>(targetEntity, propertyValueProvider, null)); - if (targetEntity.requiresPropertyPopulation()) { - return readProperties(targetEntity, instance, propertyValueProvider); - } - - return instance; + return targetEntity.requiresPropertyPopulation() ? readProperties(targetEntity, instance, propertyValueProvider) + : instance; } protected R readProperties(ElasticsearchPersistentEntity entity, R instance, @@ -153,6 +196,7 @@ public class ElasticsearchEntityMapper implements return accessor.getBean(); } + @SuppressWarnings("unchecked") protected R readValue(@Nullable Object source, ElasticsearchPersistentProperty property, TypeInformation targetType) { @@ -160,20 +204,19 @@ public class ElasticsearchEntityMapper implements return null; } - Class rawType = targetType.getType(); + Class rawType = targetType.getType(); if (conversions.hasCustomReadTarget(source.getClass(), rawType)) { - return (R) conversionService.convert(source, rawType); + return rawType.cast(conversionService.convert(source, rawType)); } else if (source instanceof List) { return readCollectionValue((List) source, property, targetType); } else if (source instanceof Map) { return readMapValue((Map) source, property, targetType); - } else if (Enum.class.isAssignableFrom(rawType)) { - return (R) Enum.valueOf((Class) rawType, source.toString()); } return (R) readSimpleValue(source, targetType); } + @SuppressWarnings("unchecked") private R readMapValue(@Nullable Map source, ElasticsearchPersistentProperty property, TypeInformation targetType) { @@ -186,10 +229,10 @@ public class ElasticsearchEntityMapper implements return readEntity(targetEntity, source); } - Map target = new LinkedHashMap(); + Map target = new LinkedHashMap<>(); for (Entry entry : source.entrySet()) { - if (conversions.isSimpleType(entry.getValue().getClass())) { + if (isSimpleType(entry.getValue())) { target.put(entry.getKey(), readSimpleValue(entry.getValue(), targetType.isMap() ? targetType.getComponentType() : targetType)); } else { @@ -211,13 +254,13 @@ public class ElasticsearchEntityMapper implements } else { target.put(entry.getKey(), readEntity(targetEntity, (Map) entry.getValue())); } - } } return (R) target; } + @SuppressWarnings("unchecked") private R readCollectionValue(@Nullable List source, ElasticsearchPersistentProperty property, TypeInformation targetType) { @@ -225,12 +268,11 @@ public class ElasticsearchEntityMapper implements return null; } - List sourceList = source; - Collection target = createCollectionForValue(targetType, sourceList.size()); + Collection target = createCollectionForValue(targetType, source.size()); - for (Object value : sourceList) { + for (Object value : source) { - if (conversions.isSimpleType(value.getClass())) { + if (isSimpleType(value)) { target.add( readSimpleValue(value, targetType.getComponentType() != null ? targetType.getComponentType() : targetType)); } else { @@ -246,23 +288,24 @@ public class ElasticsearchEntityMapper implements return (R) target; } - protected Object readSimpleValue(@Nullable Object value, TypeInformation targetType) { + @SuppressWarnings("unchecked") + private Object readSimpleValue(@Nullable Object value, TypeInformation targetType) { - if (value == null) { - return null; - } + Class target = targetType.getType(); - if (ClassTypeInformation.OBJECT.equals(targetType) - || (targetType != null && value.getClass().equals(targetType.getActualType()))) { + if (value == null || target == null || ClassUtils.isAssignableValue(target, value)) { return value; } - if (conversionService.canConvert(value.getClass(), targetType.getType())) { - return conversionService.convert(value, targetType.getType()); + if (conversions.hasCustomReadTarget(value.getClass(), target)) { + return conversionService.convert(value, target); } - throw new MappingException( - String.format("Unable to map %s of type %s to %s", value, value.getClass(), targetType.getType())); + if (Enum.class.isAssignableFrom(target)) { + return Enum.valueOf((Class) target, value.toString()); + } + + return conversionService.convert(value, target); } // --> WRITE @@ -275,6 +318,7 @@ public class ElasticsearchEntityMapper implements return target; } + @SuppressWarnings("unchecked") @Override public void write(@Nullable Object source, Map sink) { @@ -284,12 +328,12 @@ public class ElasticsearchEntityMapper implements if (source instanceof Map) { - sink.putAll((Map) source); + sink.putAll((Map) source); return; } Class entityType = ClassUtils.getUserClass(source.getClass()); - TypeInformation type = ClassTypeInformation.from(entityType); + TypeInformation type = ClassTypeInformation.from(entityType); if (requiresTypeHint(type, source.getClass(), null)) { typeMapper.writeType(source.getClass(), sink); @@ -337,6 +381,7 @@ public class ElasticsearchEntityMapper implements if (requiresTypeHint(entity.getTypeInformation(), source.getClass(), containingStructure)) { typeMapper.writeType(source.getClass(), sink); } + writeProperties(entity, accessor, sink); } @@ -355,7 +400,7 @@ public class ElasticsearchEntityMapper implements continue; } - if (!conversions.isSimpleType(value.getClass())) { + if (!isSimpleType(value)) { writeProperty(property, value, sink); } else { sink.put(property.getFieldName(), getWriteSimpleValue(value)); @@ -393,15 +438,20 @@ public class ElasticsearchEntityMapper implements protected Object getWriteSimpleValue(Object value) { - Optional> customWriteTarget = conversions.getCustomWriteTarget(value.getClass()); - - if (!customWriteTarget.isPresent()) { - return Enum.class.isAssignableFrom(value.getClass()) ? ((Enum) value).name() : value; + if (value == null) { + return null; } - return conversionService.convert(value, customWriteTarget.get()); + Optional> customTarget = conversions.getCustomWriteTarget(value.getClass()); + + if (customTarget.isPresent()) { + return conversionService.convert(value, customTarget.get()); + } + + return Enum.class.isAssignableFrom(value.getClass()) ? ((Enum) value).name() : value; } + @SuppressWarnings("unchecked") protected Object getWriteComplexValue(ElasticsearchPersistentProperty property, TypeInformation typeHint, Object value) { @@ -412,7 +462,7 @@ public class ElasticsearchEntityMapper implements return writeMapValue((Map) value, property, typeHint); } - if (property.isEntity() || !conversions.isSimpleType(value.getClass())) { + if (property.isEntity() || !isSimpleType(value)) { return writeEntity(value, property, typeHint); } @@ -433,7 +483,7 @@ public class ElasticsearchEntityMapper implements Streamable> mapSource = Streamable.of(value.entrySet()); if (!typeHint.getActualType().getType().equals(Object.class) - && conversions.isSimpleType(typeHint.getMapValueType().getType())) { + && isSimpleType(typeHint.getMapValueType().getType())) { mapSource.forEach(it -> target.put(it.getKey(), getWriteSimpleValue(it.getValue()))); } else { @@ -442,7 +492,7 @@ public class ElasticsearchEntityMapper implements Object converted = null; if (it.getValue() != null) { - if (conversions.isSimpleType(it.getValue().getClass())) { + if (isSimpleType(it.getValue())) { converted = getWriteSimpleValue(it.getValue()); } else { converted = getWriteComplexValue(property, ClassTypeInformation.from(it.getValue().getClass()), @@ -451,7 +501,6 @@ public class ElasticsearchEntityMapper implements } target.put(it.getKey(), converted); - }); } @@ -461,23 +510,21 @@ public class ElasticsearchEntityMapper implements private Object writeCollectionValue(Object value, ElasticsearchPersistentProperty property, TypeInformation typeHint) { - Streamable collectionSource = value instanceof Iterable ? Streamable.of((Iterable) value) + Streamable collectionSource = value instanceof Iterable ? Streamable.of((Iterable) value) : Streamable.of(ObjectUtils.toObjectArray(value)); List target = new ArrayList<>(); - if (!typeHint.getActualType().getType().equals(Object.class) - && conversions.isSimpleType(typeHint.getActualType().getType())) { - + if (!typeHint.getActualType().getType().equals(Object.class) && isSimpleType(typeHint.getActualType().getType())) { collectionSource.map(this::getWriteSimpleValue).forEach(target::add); } else { - Streamable.of((Iterable) value).map(it -> { + collectionSource.map(it -> { if (it == null) { return null; } - if (conversions.isSimpleType(it.getClass())) { + if (isSimpleType(it)) { return getWriteSimpleValue(it); } @@ -488,48 +535,6 @@ public class ElasticsearchEntityMapper implements return target; } - // --> GETTERS / SETTERS - - @Override - public MappingContext, ElasticsearchPersistentProperty> getMappingContext() { - return mappingContext; - } - - @Override - public ConversionService getConversionService() { - return conversionService; - } - - /** - * Set the {@link CustomConversions} to be applied during the mapping process.
- * Conversions are registered after {@link #afterPropertiesSet() bean initialization}. - * - * @param conversions must not be {@literal null}. - */ - public void setConversions(CustomConversions conversions) { - this.conversions = conversions; - } - - /** - * Set the {@link ElasticsearchTypeMapper} to use for reading / writing type hints. - * - * @param typeMapper must not be {@literal null}. - */ - public void setTypeMapper(ElasticsearchTypeMapper typeMapper) { - this.typeMapper = typeMapper; - } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - @Override - public void afterPropertiesSet() { - - DateFormatterRegistrar.addDateConverters(conversionService); - conversions.registerConvertersIn(conversionService); - } - // --> LEGACY @Override @@ -549,21 +554,23 @@ public class ElasticsearchEntityMapper implements // --> PRIVATE HELPERS private boolean requiresTypeHint(TypeInformation type, Class actualType, - @Nullable TypeInformation containingStructure) { + @Nullable TypeInformation container) { - if (containingStructure != null) { + if (container != null) { - if (containingStructure.isCollectionLike()) { - if (containingStructure.getActualType().equals(type) && type.getType().equals(actualType)) { + if (container.isCollectionLike()) { + if (type.equals(container.getActualType()) && type.getType().equals(actualType)) { return false; } } - if (containingStructure.isMap()) { - if (containingStructure.getMapValueType().equals(type) && type.getType().equals(actualType)) { + + if (container.isMap()) { + if (type.equals(container.getMapValueType()) && type.getType().equals(actualType)) { return false; } } - if (containingStructure.equals(type) && type.getType().equals(actualType)) { + + if (container.equals(type) && type.getType().equals(actualType)) { return false; } } @@ -574,7 +581,7 @@ public class ElasticsearchEntityMapper implements /** * Compute the type to use by checking the given entity against the store type; - * + * * @param entity * @param source * @return @@ -600,12 +607,12 @@ public class ElasticsearchEntityMapper implements private ElasticsearchPersistentEntity computeGenericValueTypeForRead(ElasticsearchPersistentProperty property, Object value) { - return property.getTypeInformation().getActualType().equals(ClassTypeInformation.OBJECT) + return ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType()) ? mappingContext.getRequiredPersistentEntity(value.getClass()) : mappingContext.getRequiredPersistentEntity(property.getTypeInformation().getActualType()); } - private Collection createCollectionForValue(TypeInformation collectionTypeInformation, int size) { + private Collection createCollectionForValue(TypeInformation collectionTypeInformation, int size) { Class collectionType = collectionTypeInformation.isSubTypeOf(Collection.class) // ? collectionTypeInformation.getType() // @@ -618,19 +625,24 @@ public class ElasticsearchEntityMapper implements return collectionTypeInformation.getType().isArray() // ? new ArrayList<>(size) // : CollectionFactory.createCollection(collectionType, componentType.getType(), size); + } + private boolean isSimpleType(Object value) { + return isSimpleType(value.getClass()); + } + + private boolean isSimpleType(Class type) { + return conversions.isSimpleType(type); } // --> OHTER STUFF + @RequiredArgsConstructor class ElasticsearchPropertyValueProvider implements PropertyValueProvider { final MapValueAccessor mapValueAccessor; - public ElasticsearchPropertyValueProvider(MapValueAccessor mapValueAccessor) { - this.mapValueAccessor = mapValueAccessor; - } - + @SuppressWarnings("unchecked") @Override public T getPropertyValue(ElasticsearchPersistentProperty property) { return (T) readValue(mapValueAccessor.get(property), property, property.getTypeInformation()); @@ -670,13 +682,14 @@ public class ElasticsearchEntityMapper implements return result; } + @SuppressWarnings("unchecked") private Map getAsMap(Object result) { if (result instanceof Map) { return (Map) result; } - throw new IllegalArgumentException(String.format("%s is no Map.", result)); + throw new IllegalArgumentException(String.format("%s is not a Map.", result)); } } 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 e32e88740..563328a6f 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java @@ -24,16 +24,7 @@ import static org.springframework.util.StringUtils.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.Set; +import java.util.*; import org.apache.http.util.EntityUtils; import org.elasticsearch.action.ActionFuture; @@ -877,7 +868,7 @@ public class ElasticsearchRestTemplate SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName) .withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build(); - SearchResultMapper onlyIdResultMapper = new SearchResultMapper() { + SearchResultMapper onlyIdResultMapper = new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List result = new ArrayList(); @@ -886,14 +877,9 @@ public class ElasticsearchRestTemplate result.add(id); } if (result.size() > 0) { - return new AggregatedPageImpl((List) result, response.getScrollId()); + return new AggregatedPageImpl<>((List) result, response.getScrollId()); } - return new AggregatedPageImpl(Collections.EMPTY_LIST, response.getScrollId()); - } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; + return new AggregatedPageImpl<>(Collections.emptyList(), response.getScrollId()); } }; @@ -1458,7 +1444,7 @@ public class ElasticsearchRestTemplate /** * It takes two steps to create a List from the elasticsearch http response because the aliases field * is actually a Map by alias name, but the alias name is on the AliasMetadata. - * + * * @param aliasResponse * @return */ 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 461f2326a..86f3f73f3 100755 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -755,7 +755,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, EsClient< SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName) .withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build(); - SearchResultMapper onlyIdResultMapper = new SearchResultMapper() { + SearchResultMapper onlyIdResultMapper = new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List result = new ArrayList(); @@ -766,12 +766,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, EsClient< if (result.size() > 0) { return new AggregatedPageImpl((List) result, response.getScrollId()); } - return new AggregatedPageImpl(Collections.EMPTY_LIST, response.getScrollId()); - } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; + return new AggregatedPageImpl(Collections.emptyList(), response.getScrollId()); } }; 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 fc38582fa..b9e222bb4 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ResultsMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ResultsMapper.java @@ -86,14 +86,14 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult Object mappedResult = getEntityMapper().readObject(source, type); if (mappedResult == null) { - return (T) mappedResult; + return (T) null; } if (type.isInterface() || !ClassUtils.isAssignableValue(type, mappedResult)) { return getProjectionFactory().createProjection(type, mappedResult); } - return (T) mappedResult; + return type.cast(mappedResult); } /** @@ -120,13 +120,13 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult Object mappedResult = getEntityMapper().readObject(source, type); if (mappedResult == null) { - return (T) mappedResult; + return null; } if (type.isInterface()) { return getProjectionFactory().createProjection(type, mappedResult); } - return (T) mappedResult; + return type.cast(mappedResult); } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/SearchResultMapperAdapter.java b/src/main/java/org/springframework/data/elasticsearch/core/SearchResultMapperAdapter.java new file mode 100644 index 000000000..83a7f42bf --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/SearchResultMapperAdapter.java @@ -0,0 +1,49 @@ +/* + * 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 + * + * 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.core; + +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.search.SearchHit; +import org.springframework.data.domain.Pageable; +import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage; + +/** + * Adapter utility for {@link SearchResultMapper} that wish to implement a subset of mapping methods. Default + * implementations throw {@link UnsupportedOperationException}. + * + * @author Mark Paluch + * @since 3.2 + */ +abstract class SearchResultMapperAdapter implements SearchResultMapper { + + /* + * (non-Javadoc) + * @see org.springframework.data.elasticsearch.core.SearchResultMapper#mapResults(org.elasticsearch.action.search.SearchResponse, java.lang.Class, org.springframework.data.domain.Pageable) + */ + @Override + public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.elasticsearch.core.SearchResultMapper#mapSearchHit(org.elasticsearch.search.SearchHit, java.lang.Class) + */ + @Override + public T mapSearchHit(SearchHit searchHit, Class type) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/DateTimeConverters.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/DateTimeConverters.java index 455bd4cd0..61865582b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/DateTimeConverters.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/DateTimeConverters.java @@ -30,7 +30,6 @@ import org.springframework.core.convert.converter.Converter; * @author Rizwan Idrees * @author Mohsin Husen */ - public final class DateTimeConverters { private static DateTimeFormatter formatter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC); diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/DefaultElasticsearchTypeMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/DefaultElasticsearchTypeMapper.java new file mode 100644 index 000000000..6f02e79da --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/DefaultElasticsearchTypeMapper.java @@ -0,0 +1,104 @@ +/* + * 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 + * + * 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.core.convert; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.springframework.data.convert.DefaultTypeMapper; +import org.springframework.data.convert.SimpleTypeInformationMapper; +import org.springframework.data.convert.TypeAliasAccessor; +import org.springframework.data.convert.TypeInformationMapper; +import org.springframework.data.mapping.Alias; +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.lang.Nullable; + +/** + * Elasticsearch specific {@link org.springframework.data.convert.TypeMapper} implementation. + * + * @author Christoph Strobl + * @author Mark Paluch + * @since 3.2 + */ +public class DefaultElasticsearchTypeMapper extends DefaultTypeMapper> + implements ElasticsearchTypeMapper { + + private final @Nullable String typeKey; + + public DefaultElasticsearchTypeMapper(@Nullable String typeKey) { + this(typeKey, Collections.singletonList(new SimpleTypeInformationMapper())); + } + + public DefaultElasticsearchTypeMapper(@Nullable String typeKey, + MappingContext, ?> mappingContext) { + this(typeKey, new MapTypeAliasAccessor(typeKey), mappingContext, + Collections.singletonList(new SimpleTypeInformationMapper())); + } + + public DefaultElasticsearchTypeMapper(@Nullable String typeKey, List mappers) { + this(typeKey, new MapTypeAliasAccessor(typeKey), null, mappers); + } + + public DefaultElasticsearchTypeMapper(@Nullable String typeKey, TypeAliasAccessor> accessor, + @Nullable MappingContext, ?> mappingContext, + List mappers) { + + super(accessor, mappingContext, mappers); + this.typeKey = typeKey; + } + + @Override + public boolean isTypeKey(String key) { + return typeKey != null && typeKey.equals(key); + } + + /** + * {@link TypeAliasAccessor} to store aliases in a {@link Map}. + * + * @author Christoph Strobl + */ + public static class MapTypeAliasAccessor implements TypeAliasAccessor> { + + private final @Nullable String typeKey; + + public MapTypeAliasAccessor(@Nullable String typeKey) { + this.typeKey = typeKey; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.convert.TypeAliasAccessor#readAliasFrom(java.lang.Object) + */ + public Alias readAliasFrom(Map source) { + return Alias.ofNullable(source.get(typeKey)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.convert.TypeAliasAccessor#writeTypeTo(java.lang.Object, java.lang.Object) + */ + public void writeTypeTo(Map sink, Object alias) { + + if (typeKey == null) { + return; + } + + sink.put(typeKey, alias); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchCustomConversions.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchCustomConversions.java index 868e56357..f67e99f75 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchCustomConversions.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchCustomConversions.java @@ -43,6 +43,7 @@ public class ElasticsearchCustomConversions extends CustomConversions { static { List converters = new ArrayList<>(); + converters.addAll(GeoConverters.getConvertersToRegister()); converters.add(StringToUUIDConverter.INSTANCE); converters.add(UUIDToStringConverter.INSTANCE); @@ -62,6 +63,9 @@ public class ElasticsearchCustomConversions extends CustomConversions { super(STORE_CONVERSIONS, converters); } + /** + * {@link Converter} to read a {@link UUID} from its {@link String} representation. + */ @ReadingConverter enum StringToUUIDConverter implements Converter { @@ -73,6 +77,9 @@ public class ElasticsearchCustomConversions extends CustomConversions { } } + /** + * {@link Converter} to write a {@link UUID} to its {@link String} representation. + */ @WritingConverter enum UUIDToStringConverter implements Converter { @@ -84,6 +91,9 @@ public class ElasticsearchCustomConversions extends CustomConversions { } } + /** + * {@link Converter} to read a {@link BigDecimal} from a {@link Double} value. + */ @ReadingConverter enum DoubleToBigDecimalConverter implements Converter { @@ -95,6 +105,9 @@ public class ElasticsearchCustomConversions extends CustomConversions { } } + /** + * {@link Converter} to write a {@link BigDecimal} to a {@link Double} value. + */ @WritingConverter enum BigDecimalToDoubleConverter implements Converter { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchDefaultTypeMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchDefaultTypeMapper.java deleted file mode 100644 index 4153f1f2c..000000000 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchDefaultTypeMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 - * - * 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.core.convert; - -import java.util.List; -import java.util.Map; - -import org.springframework.data.convert.DefaultTypeMapper; -import org.springframework.data.convert.TypeAliasAccessor; -import org.springframework.data.mapping.context.MappingContext; -import org.springframework.lang.Nullable; - -/** - * Elasticsearch specific {@link org.springframework.data.convert.TypeMapper} implementation. - * - * @author Christoph Strobl - * @since 3.2 - */ -class ElasticsearchDefaultTypeMapper extends DefaultTypeMapper> implements ElasticsearchTypeMapper { - - private final @Nullable String typeKey; - - ElasticsearchDefaultTypeMapper(@Nullable String typeKey, TypeAliasAccessor accessor, - @Nullable MappingContext mappingContext, List additionalMappers) { - - super(accessor, mappingContext, additionalMappers); - this.typeKey = typeKey; - } - - @Override - public boolean isTypeKey(String key) { - return typeKey != null && typeKey.equals(key); - } -} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchTypeMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchTypeMapper.java index 6f1270fb7..2125e77c6 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchTypeMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchTypeMapper.java @@ -15,17 +15,12 @@ */ package org.springframework.data.elasticsearch.core.convert; -import java.util.Collections; import java.util.Map; -import org.springframework.data.convert.SimpleTypeInformationMapper; -import org.springframework.data.convert.TypeAliasAccessor; import org.springframework.data.convert.TypeMapper; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; -import org.springframework.data.mapping.Alias; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.lang.Nullable; /** * Elasticsearch specific {@link TypeMapper} definition. @@ -48,45 +43,15 @@ public interface ElasticsearchTypeMapper extends TypeMapper> return readType(source) != null; } - static ElasticsearchTypeMapper defaultTypeMapper( - MappingContext, ElasticsearchPersistentProperty> mappingContext) { - return new ElasticsearchDefaultTypeMapper(DEFAULT_TYPE_KEY, new MapTypeAliasAccessor(DEFAULT_TYPE_KEY), - mappingContext, Collections.singletonList(new SimpleTypeInformationMapper())); - } - /** - * {@link TypeAliasAccessor} to store aliases in a {@link Map}. + * Creates a new default {@link ElasticsearchTypeMapper}. * - * @author Christoph Strobl + * @param mappingContext the mapping context. + * @return a new default {@link ElasticsearchTypeMapper}. + * @see DefaultElasticsearchTypeMapper */ - final class MapTypeAliasAccessor implements TypeAliasAccessor> { - - private final @Nullable String typeKey; - - public MapTypeAliasAccessor(@Nullable String typeKey) { - this.typeKey = typeKey; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.convert.TypeAliasAccessor#readAliasFrom(java.lang.Object) - */ - public Alias readAliasFrom(Map source) { - return Alias.ofNullable(source.get(typeKey)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.convert.TypeAliasAccessor#writeTypeTo(java.lang.Object, java.lang.Object) - */ - public void writeTypeTo(Map sink, Object alias) { - - if (typeKey == null) { - return; - } - - sink.put(typeKey, alias); - } + static ElasticsearchTypeMapper create( + MappingContext, ElasticsearchPersistentProperty> mappingContext) { + return new DefaultElasticsearchTypeMapper(DEFAULT_TYPE_KEY, mappingContext); } - } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java index ffbc365eb..ef1379b51 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java @@ -35,14 +35,17 @@ import org.springframework.util.NumberUtils; */ class GeoConverters { - static Collection getConvertersToRegister() { + static Collection getConvertersToRegister() { return Arrays.asList(PointToMapConverter.INSTANCE, MapToPointConverter.INSTANCE, GeoPointToMapConverter.INSTANCE, MapToGeoPointConverter.INSTANCE); } + /** + * {@link Converter} to write a {@link Point} to {@link Map} using {@code lat/long} properties. + */ @WritingConverter - enum PointToMapConverter implements Converter { + enum PointToMapConverter implements Converter> { INSTANCE; @@ -56,8 +59,11 @@ class GeoConverters { } } + /** + * {@link Converter} to write a {@link GeoPoint} to {@link Map} using {@code lat/long} properties. + */ @WritingConverter - enum GeoPointToMapConverter implements Converter { + enum GeoPointToMapConverter implements Converter> { INSTANCE; @@ -70,8 +76,11 @@ class GeoConverters { } } + /** + * {@link Converter} to read a {@link Point} from {@link Map} using {@code lat/long} properties. + */ @ReadingConverter - enum MapToPointConverter implements Converter { + enum MapToPointConverter implements Converter, Point> { INSTANCE; @@ -84,8 +93,11 @@ class GeoConverters { } } + /** + * {@link Converter} to read a {@link GeoPoint} from {@link Map} using {@code lat/long} properties. + */ @ReadingConverter - enum MapToGeoPointConverter implements Converter { + enum MapToGeoPointConverter implements Converter, GeoPoint> { INSTANCE; 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 7b0ce4655..9a0bfb429 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -15,6 +15,12 @@ */ package org.springframework.data.elasticsearch.core; +import static org.apache.commons.lang.RandomStringUtils.*; +import static org.elasticsearch.index.query.QueryBuilders.*; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.springframework.data.elasticsearch.utils.IndexBuilder.*; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -62,11 +68,6 @@ import org.springframework.data.elasticsearch.entities.SampleEntity; import org.springframework.data.elasticsearch.entities.SampleMappingEntity; import org.springframework.data.elasticsearch.entities.UseServerConfigurationEntity; import org.springframework.data.util.CloseableIterator; -import static org.apache.commons.lang.RandomStringUtils.*; -import static org.elasticsearch.index.query.QueryBuilders.*; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.springframework.data.elasticsearch.utils.IndexBuilder.*; /** * Base for testing rest/transport templates @@ -808,7 +809,7 @@ public class ElasticsearchTemplateTests { SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withIndices(INDEX_NAME) .withTypes(TYPE_NAME).withFields("message").build(); // when - Page page = elasticsearchTemplate.queryForPage(searchQuery, String.class, new SearchResultMapper() { + Page page = elasticsearchTemplate.queryForPage(searchQuery, String.class, new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List values = new ArrayList<>(); @@ -817,11 +818,6 @@ public class ElasticsearchTemplateTests { } return new AggregatedPageImpl<>((List) values); } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); // then assertThat(page, is(notNullValue())); @@ -941,10 +937,10 @@ public class ElasticsearchTemplateTests { } - final SearchResultMapper searchResultMapper = new SearchResultMapper() { + final SearchResultMapper searchResultMapper = new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { - List result = new ArrayList(); + List result = new ArrayList<>(); for (SearchHit searchHit : response.getHits()) { if (response.getHits().getHits().length <= 0) { return new AggregatedPageImpl(Collections.EMPTY_LIST, response.getScrollId()); @@ -959,12 +955,7 @@ public class ElasticsearchTemplateTests { if (result.size() > 0) { return new AggregatedPageImpl((List) result, response.getScrollId()); } - return new AggregatedPageImpl(Collections.EMPTY_LIST, response.getScrollId()); - } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; + return new AggregatedPageImpl(Collections.emptyList(), response.getScrollId()); } }; @@ -1347,7 +1338,8 @@ public class ElasticsearchTemplateTests { .withHighlightFields(message.toArray(new HighlightBuilder.Field[message.size()])) .build(); - Page sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() { + Page sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, + new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List chunk = new ArrayList<>(); @@ -1366,11 +1358,6 @@ public class ElasticsearchTemplateTests { } return null; } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage)); @@ -1409,7 +1396,7 @@ public class ElasticsearchTemplateTests { .build(); // when - elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() { + elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { for (SearchHit searchHit : response.getHits()) { @@ -1425,11 +1412,6 @@ public class ElasticsearchTemplateTests { } return null; } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); } @@ -1458,7 +1440,7 @@ public class ElasticsearchTemplateTests { .withHighlightFields(new HighlightBuilder.Field("message")) .build(); // when - elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() { + elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { for (SearchHit searchHit : response.getHits()) { @@ -1471,11 +1453,6 @@ public class ElasticsearchTemplateTests { } return null; } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); } @@ -1621,7 +1598,8 @@ public class ElasticsearchTemplateTests { .withTypes(TYPE_NAME) .build(); // then - Page page = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() { + Page page = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, + new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List values = new ArrayList<>(); @@ -1633,11 +1611,6 @@ public class ElasticsearchTemplateTests { } return new AggregatedPageImpl<>((List) values); } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); assertThat(page, is(notNullValue())); assertThat(page.getContent().size(), is(1)); @@ -1826,7 +1799,8 @@ public class ElasticsearchTemplateTests { // then SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices(INDEX_NAME) .withTypes(TYPE_NAME).withQuery(matchAllQuery()).build(); - Page sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, Map.class, new SearchResultMapper() { + Page sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, Map.class, + new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List chunk = new ArrayList<>(); @@ -1847,11 +1821,6 @@ public class ElasticsearchTemplateTests { } return null; } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); assertThat(sampleEntities.getTotalElements(), is(equalTo(2L))); assertThat(sampleEntities.getContent().get(0).get("userId"), is(person1.get("userId"))); @@ -2400,7 +2369,8 @@ public class ElasticsearchTemplateTests { // When SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withTypes("hetro").withIndices(INDEX_1_NAME, INDEX_2_NAME).build(); - Page page = elasticsearchTemplate.queryForPage(searchQuery, ResultAggregator.class, new SearchResultMapper() { + Page page = elasticsearchTemplate.queryForPage(searchQuery, ResultAggregator.class, + new SearchResultMapperAdapter() { @Override public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) { List values = new ArrayList<>(); @@ -2412,11 +2382,6 @@ public class ElasticsearchTemplateTests { } return new AggregatedPageImpl<>((List) values); } - - @Override - public T mapSearchHit(SearchHit searchHit, Class type) { - return null; - } }); assertThat(page.getTotalElements(), is(2l));