mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-23 20:42:11 +00:00
DATAES-530 - Polishing.
Fix generics in ElasticsearchEntityMapper. Extract methods. Move enum conversion handling to simple type handling for symmetric implementation. Swap comparison of nullable types to avoid potential null dereference. Rename ElasticsearchDefaultTypeMapper to DefaultElasticsearchTypeMapper. Move MapTypeAliasAccessor to DefaultElasticsearchTypeMapper. Introduce SearchResultMapperAdapter to avoid empty method implementations in anonymous classes. Javadoc, reference docs, formatting. Original Pull Request: #237
This commit is contained in:
parent
a64af54e26
commit
c3e7056d7b
@ -66,13 +66,26 @@ for `Converter` registration.
|
|||||||
<3> Optionally set `CustomConversions` if applicable.
|
<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]]
|
[[elasticsearch.mapping.meta-model.rules]]
|
||||||
=== Mapping Rules
|
=== Mapping Rules
|
||||||
|
|
||||||
==== Type Hints
|
==== Type Hints
|
||||||
|
|
||||||
Mapping uses _type hints_ embedded in the document sent to the server to allow generic type mapping. Those type hints are
|
Mapping uses _type hints_ embedded in the document sent to the server to allow generic type mapping.
|
||||||
represented as `_class` attributes within the document on the server and will be written for each aggregate root.
|
Those type hints are represented as `_class` attributes within the document and are written for each aggregate root.
|
||||||
|
|
||||||
.Type Hints
|
.Type Hints
|
||||||
====
|
====
|
||||||
@ -123,8 +136,7 @@ public class Person {
|
|||||||
<1> The configured alias is used when writing the entity.
|
<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
|
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.
|
||||||
actual value type does not match the properties declaration.
|
|
||||||
|
|
||||||
==== Geospatial Types
|
==== Geospatial Types
|
||||||
|
|
||||||
@ -152,8 +164,7 @@ public class Address {
|
|||||||
|
|
||||||
==== Collections
|
==== Collections
|
||||||
|
|
||||||
For values inside Collections apply the same mapping rules as for aggregate roots when it comes to _type hints_
|
For values inside Collections apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <<elasticsearch.mapping.meta-model.conversions>>.
|
||||||
and <<elasticsearch.mapping.meta-model.conversions>>.
|
|
||||||
|
|
||||||
.Collections
|
.Collections
|
||||||
====
|
====
|
||||||
@ -179,8 +190,7 @@ public class Person {
|
|||||||
|
|
||||||
==== Maps
|
==== Maps
|
||||||
|
|
||||||
For values inside Maps apply the same mapping rules as for aggregate roots when it comes to _type hints_
|
For values inside Maps apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <<elasticsearch.mapping.meta-model.conversions>>.
|
||||||
and <<elasticsearch.mapping.meta-model.conversions>>.
|
|
||||||
However the Map key needs to a String to be processed by Elasticsearch.
|
However the Map key needs to a String to be processed by Elasticsearch.
|
||||||
|
|
||||||
.Collections
|
.Collections
|
||||||
@ -214,8 +224,7 @@ public class Person {
|
|||||||
[[elasticsearch.mapping.meta-model.conversions]]
|
[[elasticsearch.mapping.meta-model.conversions]]
|
||||||
=== Custom Conversions
|
=== Custom Conversions
|
||||||
|
|
||||||
Looking at the `Configuration` from the <<elasticsearch.mapping.meta-model, previous section>> `ElasticsearchCustomConversions`
|
Looking at the `Configuration` from the <<elasticsearch.mapping.meta-model, previous section>> `ElasticsearchCustomConversions` allows registering specific rules for mapping domain and simple types.
|
||||||
allows to register specific rules for mapping domain and simple types.
|
|
||||||
|
|
||||||
.Meta Model Object Mapping Configuration
|
.Meta Model Object Mapping Configuration
|
||||||
====
|
====
|
||||||
|
@ -72,15 +72,14 @@ public class ElasticsearchConfigurationSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link EntityMapper} used for mapping source <> DomainType. <br />
|
* Returns the {@link EntityMapper} used for mapping between the source and domain type. <br />
|
||||||
* <strong>Hint</strong>: you can use {@link org.springframework.data.elasticsearch.core.ElasticsearchEntityMapper} as
|
* <strong>Hint</strong>: you can use {@link org.springframework.data.elasticsearch.core.ElasticsearchEntityMapper} as
|
||||||
* an alternative to the {@link DefaultEntityMapper}.
|
* an alternative to the {@link DefaultEntityMapper}.
|
||||||
*
|
*
|
||||||
* <pre>{@code
|
* <pre class="code">
|
||||||
* ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(),
|
* ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(),
|
||||||
* new DefaultConversionService());
|
* new DefaultConversionService());
|
||||||
* entityMapper.setConversions(elasticsearchCustomConversions());
|
* entityMapper.setConversions(elasticsearchCustomConversions());
|
||||||
* }
|
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
|
@ -28,14 +28,20 @@ public abstract class AbstractResultMapper implements ResultsMapper {
|
|||||||
private final EntityMapper entityMapper;
|
private final EntityMapper entityMapper;
|
||||||
private final ProjectionFactory projectionFactory;
|
private final ProjectionFactory projectionFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link AbstractResultMapper}.
|
||||||
|
*
|
||||||
|
* @param entityMapper must not be {@literal null}.
|
||||||
|
*/
|
||||||
public AbstractResultMapper(EntityMapper entityMapper) {
|
public AbstractResultMapper(EntityMapper entityMapper) {
|
||||||
this(entityMapper, new SpelAwareProxyProjectionFactory());
|
this(entityMapper, new SpelAwareProxyProjectionFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Create a new {@link AbstractResultMapper}.
|
||||||
*
|
*
|
||||||
* @param entityMapper
|
* @param entityMapper must not be {@literal null}.
|
||||||
* @param projectionFactory
|
* @param projectionFactory must not be {@literal null}.
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public AbstractResultMapper(EntityMapper entityMapper, ProjectionFactory projectionFactory) {
|
public AbstractResultMapper(EntityMapper entityMapper, ProjectionFactory projectionFactory) {
|
||||||
@ -47,6 +53,10 @@ public abstract class AbstractResultMapper implements ResultsMapper {
|
|||||||
this.projectionFactory = projectionFactory;
|
this.projectionFactory = projectionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.elasticsearch.core.ResultsMapper#getEntityMapper()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public EntityMapper getEntityMapper() {
|
public EntityMapper getEntityMapper() {
|
||||||
return this.entityMapper;
|
return this.entityMapper;
|
||||||
@ -58,6 +68,6 @@ public abstract class AbstractResultMapper implements ResultsMapper {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ProjectionFactory getProjectionFactory() {
|
public ProjectionFactory getProjectionFactory() {
|
||||||
return projectionFactory;
|
return this.projectionFactory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,12 +88,11 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
|||||||
this.mappingContext = mappingContext;
|
this.mappingContext = mappingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EntityMapper initEntityMapper(
|
private static EntityMapper initEntityMapper(
|
||||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
|
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
|
||||||
|
|
||||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||||
return new DefaultEntityMapper(mappingContext);
|
return new DefaultEntityMapper(mappingContext);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core;
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
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.convert.ElasticsearchTypeMapper;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
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.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||||
@ -76,7 +77,49 @@ public class ElasticsearchEntityMapper implements
|
|||||||
|
|
||||||
this.mappingContext = mappingContext;
|
this.mappingContext = mappingContext;
|
||||||
this.conversionService = conversionService != null ? conversionService : new DefaultConversionService();
|
this.conversionService = conversionService != null ? conversionService : new DefaultConversionService();
|
||||||
this.typeMapper = ElasticsearchTypeMapper.defaultTypeMapper(mappingContext);
|
this.typeMapper = ElasticsearchTypeMapper.create(mappingContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --> GETTERS / SETTERS
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> getMappingContext() {
|
||||||
|
return mappingContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversionService getConversionService() {
|
||||||
|
return conversionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link CustomConversions} to be applied during the mapping process. <br />
|
||||||
|
* 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
|
// --> READ
|
||||||
@ -86,12 +129,14 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return read(targetType, source);
|
return read(targetType, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <R> R read(Class<R> type, Map<String, Object> source) {
|
public <R> R read(Class<R> type, Map<String, Object> source) {
|
||||||
return doRead(source, ClassTypeInformation.from((Class<R>) ClassUtils.getUserClass(type)));
|
return doRead(source, ClassTypeInformation.from((Class<R>) ClassUtils.getUserClass(type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Nullable
|
@Nullable
|
||||||
protected <R> R doRead(Map<String, Object> source, TypeInformation<R> typeHint) {
|
protected <R> R doRead(Map<String, Object> source, TypeInformation<R> typeHint) {
|
||||||
|
|
||||||
@ -113,6 +158,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return readEntity(entity, source);
|
return readEntity(entity, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected <R> R readEntity(ElasticsearchPersistentEntity<?> entity, Map<String, Object> source) {
|
protected <R> R readEntity(ElasticsearchPersistentEntity<?> entity, Map<String, Object> source) {
|
||||||
|
|
||||||
ElasticsearchPersistentEntity<?> targetEntity = computeClosestEntity(entity, source);
|
ElasticsearchPersistentEntity<?> targetEntity = computeClosestEntity(entity, source);
|
||||||
@ -125,11 +171,8 @@ public class ElasticsearchEntityMapper implements
|
|||||||
R instance = (R) instantiator.createInstance(targetEntity,
|
R instance = (R) instantiator.createInstance(targetEntity,
|
||||||
new PersistentEntityParameterValueProvider<>(targetEntity, propertyValueProvider, null));
|
new PersistentEntityParameterValueProvider<>(targetEntity, propertyValueProvider, null));
|
||||||
|
|
||||||
if (targetEntity.requiresPropertyPopulation()) {
|
return targetEntity.requiresPropertyPopulation() ? readProperties(targetEntity, instance, propertyValueProvider)
|
||||||
return readProperties(targetEntity, instance, propertyValueProvider);
|
: instance;
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <R> R readProperties(ElasticsearchPersistentEntity<?> entity, R instance,
|
protected <R> R readProperties(ElasticsearchPersistentEntity<?> entity, R instance,
|
||||||
@ -153,6 +196,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return accessor.getBean();
|
return accessor.getBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected <R> R readValue(@Nullable Object source, ElasticsearchPersistentProperty property,
|
protected <R> R readValue(@Nullable Object source, ElasticsearchPersistentProperty property,
|
||||||
TypeInformation<R> targetType) {
|
TypeInformation<R> targetType) {
|
||||||
|
|
||||||
@ -160,20 +204,19 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> rawType = targetType.getType();
|
Class<R> rawType = targetType.getType();
|
||||||
if (conversions.hasCustomReadTarget(source.getClass(), rawType)) {
|
if (conversions.hasCustomReadTarget(source.getClass(), rawType)) {
|
||||||
return (R) conversionService.convert(source, rawType);
|
return rawType.cast(conversionService.convert(source, rawType));
|
||||||
} else if (source instanceof List) {
|
} else if (source instanceof List) {
|
||||||
return readCollectionValue((List) source, property, targetType);
|
return readCollectionValue((List) source, property, targetType);
|
||||||
} else if (source instanceof Map) {
|
} else if (source instanceof Map) {
|
||||||
return readMapValue((Map<String, Object>) source, property, targetType);
|
return readMapValue((Map<String, Object>) source, property, targetType);
|
||||||
} else if (Enum.class.isAssignableFrom(rawType)) {
|
|
||||||
return (R) Enum.valueOf((Class<Enum>) rawType, source.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (R) readSimpleValue(source, targetType);
|
return (R) readSimpleValue(source, targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private <R> R readMapValue(@Nullable Map<String, Object> source, ElasticsearchPersistentProperty property,
|
private <R> R readMapValue(@Nullable Map<String, Object> source, ElasticsearchPersistentProperty property,
|
||||||
TypeInformation<R> targetType) {
|
TypeInformation<R> targetType) {
|
||||||
|
|
||||||
@ -186,10 +229,10 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return readEntity(targetEntity, source);
|
return readEntity(targetEntity, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> target = new LinkedHashMap();
|
Map<String, Object> target = new LinkedHashMap<>();
|
||||||
for (Entry<String, Object> entry : source.entrySet()) {
|
for (Entry<String, Object> entry : source.entrySet()) {
|
||||||
|
|
||||||
if (conversions.isSimpleType(entry.getValue().getClass())) {
|
if (isSimpleType(entry.getValue())) {
|
||||||
target.put(entry.getKey(),
|
target.put(entry.getKey(),
|
||||||
readSimpleValue(entry.getValue(), targetType.isMap() ? targetType.getComponentType() : targetType));
|
readSimpleValue(entry.getValue(), targetType.isMap() ? targetType.getComponentType() : targetType));
|
||||||
} else {
|
} else {
|
||||||
@ -211,13 +254,13 @@ public class ElasticsearchEntityMapper implements
|
|||||||
} else {
|
} else {
|
||||||
target.put(entry.getKey(), readEntity(targetEntity, (Map) entry.getValue()));
|
target.put(entry.getKey(), readEntity(targetEntity, (Map) entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (R) target;
|
return (R) target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private <R> R readCollectionValue(@Nullable List<?> source, ElasticsearchPersistentProperty property,
|
private <R> R readCollectionValue(@Nullable List<?> source, ElasticsearchPersistentProperty property,
|
||||||
TypeInformation<R> targetType) {
|
TypeInformation<R> targetType) {
|
||||||
|
|
||||||
@ -225,12 +268,11 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<?> sourceList = source;
|
Collection<Object> target = createCollectionForValue(targetType, source.size());
|
||||||
Collection target = createCollectionForValue(targetType, sourceList.size());
|
|
||||||
|
|
||||||
for (Object value : sourceList) {
|
for (Object value : source) {
|
||||||
|
|
||||||
if (conversions.isSimpleType(value.getClass())) {
|
if (isSimpleType(value)) {
|
||||||
target.add(
|
target.add(
|
||||||
readSimpleValue(value, targetType.getComponentType() != null ? targetType.getComponentType() : targetType));
|
readSimpleValue(value, targetType.getComponentType() != null ? targetType.getComponentType() : targetType));
|
||||||
} else {
|
} else {
|
||||||
@ -246,23 +288,24 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return (R) target;
|
return (R) target;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object readSimpleValue(@Nullable Object value, TypeInformation<?> targetType) {
|
@SuppressWarnings("unchecked")
|
||||||
|
private Object readSimpleValue(@Nullable Object value, TypeInformation<?> targetType) {
|
||||||
|
|
||||||
if (value == null) {
|
Class<?> target = targetType.getType();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ClassTypeInformation.OBJECT.equals(targetType)
|
if (value == null || target == null || ClassUtils.isAssignableValue(target, value)) {
|
||||||
|| (targetType != null && value.getClass().equals(targetType.getActualType()))) {
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversionService.canConvert(value.getClass(), targetType.getType())) {
|
if (conversions.hasCustomReadTarget(value.getClass(), target)) {
|
||||||
return conversionService.convert(value, targetType.getType());
|
return conversionService.convert(value, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new MappingException(
|
if (Enum.class.isAssignableFrom(target)) {
|
||||||
String.format("Unable to map %s of type %s to %s", value, value.getClass(), targetType.getType()));
|
return Enum.valueOf((Class<Enum>) target, value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return conversionService.convert(value, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --> WRITE
|
// --> WRITE
|
||||||
@ -275,6 +318,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void write(@Nullable Object source, Map<String, Object> sink) {
|
public void write(@Nullable Object source, Map<String, Object> sink) {
|
||||||
|
|
||||||
@ -284,12 +328,12 @@ public class ElasticsearchEntityMapper implements
|
|||||||
|
|
||||||
if (source instanceof Map) {
|
if (source instanceof Map) {
|
||||||
|
|
||||||
sink.putAll((Map) source);
|
sink.putAll((Map<String, Object>) source);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> entityType = ClassUtils.getUserClass(source.getClass());
|
Class<?> entityType = ClassUtils.getUserClass(source.getClass());
|
||||||
TypeInformation<? extends Object> type = ClassTypeInformation.from(entityType);
|
TypeInformation<?> type = ClassTypeInformation.from(entityType);
|
||||||
|
|
||||||
if (requiresTypeHint(type, source.getClass(), null)) {
|
if (requiresTypeHint(type, source.getClass(), null)) {
|
||||||
typeMapper.writeType(source.getClass(), sink);
|
typeMapper.writeType(source.getClass(), sink);
|
||||||
@ -337,6 +381,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
if (requiresTypeHint(entity.getTypeInformation(), source.getClass(), containingStructure)) {
|
if (requiresTypeHint(entity.getTypeInformation(), source.getClass(), containingStructure)) {
|
||||||
typeMapper.writeType(source.getClass(), sink);
|
typeMapper.writeType(source.getClass(), sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeProperties(entity, accessor, sink);
|
writeProperties(entity, accessor, sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +400,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conversions.isSimpleType(value.getClass())) {
|
if (!isSimpleType(value)) {
|
||||||
writeProperty(property, value, sink);
|
writeProperty(property, value, sink);
|
||||||
} else {
|
} else {
|
||||||
sink.put(property.getFieldName(), getWriteSimpleValue(value));
|
sink.put(property.getFieldName(), getWriteSimpleValue(value));
|
||||||
@ -393,15 +438,20 @@ public class ElasticsearchEntityMapper implements
|
|||||||
|
|
||||||
protected Object getWriteSimpleValue(Object value) {
|
protected Object getWriteSimpleValue(Object value) {
|
||||||
|
|
||||||
Optional<Class<?>> customWriteTarget = conversions.getCustomWriteTarget(value.getClass());
|
if (value == null) {
|
||||||
|
return null;
|
||||||
if (!customWriteTarget.isPresent()) {
|
|
||||||
return Enum.class.isAssignableFrom(value.getClass()) ? ((Enum<?>) value).name() : value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return conversionService.convert(value, customWriteTarget.get());
|
Optional<Class<?>> 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,
|
protected Object getWriteComplexValue(ElasticsearchPersistentProperty property, TypeInformation<?> typeHint,
|
||||||
Object value) {
|
Object value) {
|
||||||
|
|
||||||
@ -412,7 +462,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return writeMapValue((Map<String, Object>) value, property, typeHint);
|
return writeMapValue((Map<String, Object>) value, property, typeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.isEntity() || !conversions.isSimpleType(value.getClass())) {
|
if (property.isEntity() || !isSimpleType(value)) {
|
||||||
return writeEntity(value, property, typeHint);
|
return writeEntity(value, property, typeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +483,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
Streamable<Entry<String, Object>> mapSource = Streamable.of(value.entrySet());
|
Streamable<Entry<String, Object>> mapSource = Streamable.of(value.entrySet());
|
||||||
|
|
||||||
if (!typeHint.getActualType().getType().equals(Object.class)
|
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())));
|
mapSource.forEach(it -> target.put(it.getKey(), getWriteSimpleValue(it.getValue())));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -442,7 +492,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
Object converted = null;
|
Object converted = null;
|
||||||
if (it.getValue() != null) {
|
if (it.getValue() != null) {
|
||||||
|
|
||||||
if (conversions.isSimpleType(it.getValue().getClass())) {
|
if (isSimpleType(it.getValue())) {
|
||||||
converted = getWriteSimpleValue(it.getValue());
|
converted = getWriteSimpleValue(it.getValue());
|
||||||
} else {
|
} else {
|
||||||
converted = getWriteComplexValue(property, ClassTypeInformation.from(it.getValue().getClass()),
|
converted = getWriteComplexValue(property, ClassTypeInformation.from(it.getValue().getClass()),
|
||||||
@ -451,7 +501,6 @@ public class ElasticsearchEntityMapper implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
target.put(it.getKey(), converted);
|
target.put(it.getKey(), converted);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,23 +510,21 @@ public class ElasticsearchEntityMapper implements
|
|||||||
private Object writeCollectionValue(Object value, ElasticsearchPersistentProperty property,
|
private Object writeCollectionValue(Object value, ElasticsearchPersistentProperty property,
|
||||||
TypeInformation<?> typeHint) {
|
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));
|
: Streamable.of(ObjectUtils.toObjectArray(value));
|
||||||
|
|
||||||
List<Object> target = new ArrayList<>();
|
List<Object> target = new ArrayList<>();
|
||||||
if (!typeHint.getActualType().getType().equals(Object.class)
|
if (!typeHint.getActualType().getType().equals(Object.class) && isSimpleType(typeHint.getActualType().getType())) {
|
||||||
&& conversions.isSimpleType(typeHint.getActualType().getType())) {
|
|
||||||
|
|
||||||
collectionSource.map(this::getWriteSimpleValue).forEach(target::add);
|
collectionSource.map(this::getWriteSimpleValue).forEach(target::add);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Streamable.of((Iterable) value).map(it -> {
|
collectionSource.map(it -> {
|
||||||
|
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversions.isSimpleType(it.getClass())) {
|
if (isSimpleType(it)) {
|
||||||
return getWriteSimpleValue(it);
|
return getWriteSimpleValue(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,48 +535,6 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --> GETTERS / SETTERS
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> getMappingContext() {
|
|
||||||
return mappingContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConversionService getConversionService() {
|
|
||||||
return conversionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link CustomConversions} to be applied during the mapping process. <br />
|
|
||||||
* 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
|
// --> LEGACY
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -549,21 +554,23 @@ public class ElasticsearchEntityMapper implements
|
|||||||
// --> PRIVATE HELPERS
|
// --> PRIVATE HELPERS
|
||||||
|
|
||||||
private boolean requiresTypeHint(TypeInformation<?> type, Class<?> actualType,
|
private boolean requiresTypeHint(TypeInformation<?> type, Class<?> actualType,
|
||||||
@Nullable TypeInformation<?> containingStructure) {
|
@Nullable TypeInformation<?> container) {
|
||||||
|
|
||||||
if (containingStructure != null) {
|
if (container != null) {
|
||||||
|
|
||||||
if (containingStructure.isCollectionLike()) {
|
if (container.isCollectionLike()) {
|
||||||
if (containingStructure.getActualType().equals(type) && type.getType().equals(actualType)) {
|
if (type.equals(container.getActualType()) && type.getType().equals(actualType)) {
|
||||||
return false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (containingStructure.equals(type) && type.getType().equals(actualType)) {
|
|
||||||
|
if (container.equals(type) && type.getType().equals(actualType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,7 +581,7 @@ public class ElasticsearchEntityMapper implements
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the type to use by checking the given entity against the store type;
|
* Compute the type to use by checking the given entity against the store type;
|
||||||
*
|
*
|
||||||
* @param entity
|
* @param entity
|
||||||
* @param source
|
* @param source
|
||||||
* @return
|
* @return
|
||||||
@ -600,12 +607,12 @@ public class ElasticsearchEntityMapper implements
|
|||||||
private ElasticsearchPersistentEntity<?> computeGenericValueTypeForRead(ElasticsearchPersistentProperty property,
|
private ElasticsearchPersistentEntity<?> computeGenericValueTypeForRead(ElasticsearchPersistentProperty property,
|
||||||
Object value) {
|
Object value) {
|
||||||
|
|
||||||
return property.getTypeInformation().getActualType().equals(ClassTypeInformation.OBJECT)
|
return ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType())
|
||||||
? mappingContext.getRequiredPersistentEntity(value.getClass())
|
? mappingContext.getRequiredPersistentEntity(value.getClass())
|
||||||
: mappingContext.getRequiredPersistentEntity(property.getTypeInformation().getActualType());
|
: mappingContext.getRequiredPersistentEntity(property.getTypeInformation().getActualType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<?> createCollectionForValue(TypeInformation<?> collectionTypeInformation, int size) {
|
private Collection<Object> createCollectionForValue(TypeInformation<?> collectionTypeInformation, int size) {
|
||||||
|
|
||||||
Class<?> collectionType = collectionTypeInformation.isSubTypeOf(Collection.class) //
|
Class<?> collectionType = collectionTypeInformation.isSubTypeOf(Collection.class) //
|
||||||
? collectionTypeInformation.getType() //
|
? collectionTypeInformation.getType() //
|
||||||
@ -618,19 +625,24 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return collectionTypeInformation.getType().isArray() //
|
return collectionTypeInformation.getType().isArray() //
|
||||||
? new ArrayList<>(size) //
|
? new ArrayList<>(size) //
|
||||||
: CollectionFactory.createCollection(collectionType, componentType.getType(), 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
|
// --> OHTER STUFF
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
class ElasticsearchPropertyValueProvider implements PropertyValueProvider<ElasticsearchPersistentProperty> {
|
class ElasticsearchPropertyValueProvider implements PropertyValueProvider<ElasticsearchPersistentProperty> {
|
||||||
|
|
||||||
final MapValueAccessor mapValueAccessor;
|
final MapValueAccessor mapValueAccessor;
|
||||||
|
|
||||||
public ElasticsearchPropertyValueProvider(MapValueAccessor mapValueAccessor) {
|
@SuppressWarnings("unchecked")
|
||||||
this.mapValueAccessor = mapValueAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T getPropertyValue(ElasticsearchPersistentProperty property) {
|
public <T> T getPropertyValue(ElasticsearchPersistentProperty property) {
|
||||||
return (T) readValue(mapValueAccessor.get(property), property, property.getTypeInformation());
|
return (T) readValue(mapValueAccessor.get(property), property, property.getTypeInformation());
|
||||||
@ -670,13 +682,14 @@ public class ElasticsearchEntityMapper implements
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private Map<String, Object> getAsMap(Object result) {
|
private Map<String, Object> getAsMap(Object result) {
|
||||||
|
|
||||||
if (result instanceof Map) {
|
if (result instanceof Map) {
|
||||||
return (Map) result;
|
return (Map) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(String.format("%s is no Map.", result));
|
throw new IllegalArgumentException(String.format("%s is not a Map.", result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,16 +24,7 @@ import static org.springframework.util.StringUtils.*;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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 org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
import org.elasticsearch.action.ActionFuture;
|
import org.elasticsearch.action.ActionFuture;
|
||||||
@ -877,7 +868,7 @@ public class ElasticsearchRestTemplate
|
|||||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName)
|
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName)
|
||||||
.withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build();
|
.withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build();
|
||||||
|
|
||||||
SearchResultMapper onlyIdResultMapper = new SearchResultMapper() {
|
SearchResultMapper onlyIdResultMapper = new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<String> result = new ArrayList<String>();
|
List<String> result = new ArrayList<String>();
|
||||||
@ -886,14 +877,9 @@ public class ElasticsearchRestTemplate
|
|||||||
result.add(id);
|
result.add(id);
|
||||||
}
|
}
|
||||||
if (result.size() > 0) {
|
if (result.size() > 0) {
|
||||||
return new AggregatedPageImpl<T>((List<T>) result, response.getScrollId());
|
return new AggregatedPageImpl<>((List<T>) result, response.getScrollId());
|
||||||
}
|
}
|
||||||
return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId());
|
return new AggregatedPageImpl<>(Collections.emptyList(), response.getScrollId());
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1458,7 +1444,7 @@ public class ElasticsearchRestTemplate
|
|||||||
/**
|
/**
|
||||||
* It takes two steps to create a List<AliasMetadata> from the elasticsearch http response because the aliases field
|
* It takes two steps to create a List<AliasMetadata> from the elasticsearch http response because the aliases field
|
||||||
* is actually a Map by alias name, but the alias name is on the AliasMetadata.
|
* is actually a Map by alias name, but the alias name is on the AliasMetadata.
|
||||||
*
|
*
|
||||||
* @param aliasResponse
|
* @param aliasResponse
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -755,7 +755,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, EsClient<
|
|||||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName)
|
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName)
|
||||||
.withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build();
|
.withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build();
|
||||||
|
|
||||||
SearchResultMapper onlyIdResultMapper = new SearchResultMapper() {
|
SearchResultMapper onlyIdResultMapper = new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<String> result = new ArrayList<String>();
|
List<String> result = new ArrayList<String>();
|
||||||
@ -766,12 +766,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, EsClient<
|
|||||||
if (result.size() > 0) {
|
if (result.size() > 0) {
|
||||||
return new AggregatedPageImpl<T>((List<T>) result, response.getScrollId());
|
return new AggregatedPageImpl<T>((List<T>) result, response.getScrollId());
|
||||||
}
|
}
|
||||||
return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId());
|
return new AggregatedPageImpl<T>(Collections.emptyList(), response.getScrollId());
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,14 +86,14 @@ public interface ResultsMapper extends SearchResultMapper, GetResultMapper, Mult
|
|||||||
Object mappedResult = getEntityMapper().readObject(source, type);
|
Object mappedResult = getEntityMapper().readObject(source, type);
|
||||||
|
|
||||||
if (mappedResult == null) {
|
if (mappedResult == null) {
|
||||||
return (T) mappedResult;
|
return (T) null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.isInterface() || !ClassUtils.isAssignableValue(type, mappedResult)) {
|
if (type.isInterface() || !ClassUtils.isAssignableValue(type, mappedResult)) {
|
||||||
return getProjectionFactory().createProjection(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);
|
Object mappedResult = getEntityMapper().readObject(source, type);
|
||||||
|
|
||||||
if (mappedResult == null) {
|
if (mappedResult == null) {
|
||||||
return (T) mappedResult;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.isInterface()) {
|
if (type.isInterface()) {
|
||||||
return getProjectionFactory().createProjection(type, mappedResult);
|
return getProjectionFactory().createProjection(type, mappedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (T) mappedResult;
|
return type.cast(mappedResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> 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> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,6 @@ import org.springframework.core.convert.converter.Converter;
|
|||||||
* @author Rizwan Idrees
|
* @author Rizwan Idrees
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public final class DateTimeConverters {
|
public final class DateTimeConverters {
|
||||||
|
|
||||||
private static DateTimeFormatter formatter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
|
private static DateTimeFormatter formatter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
|
||||||
|
@ -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<Map<String, Object>>
|
||||||
|
implements ElasticsearchTypeMapper {
|
||||||
|
|
||||||
|
private final @Nullable String typeKey;
|
||||||
|
|
||||||
|
public DefaultElasticsearchTypeMapper(@Nullable String typeKey) {
|
||||||
|
this(typeKey, Collections.singletonList(new SimpleTypeInformationMapper()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultElasticsearchTypeMapper(@Nullable String typeKey,
|
||||||
|
MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext) {
|
||||||
|
this(typeKey, new MapTypeAliasAccessor(typeKey), mappingContext,
|
||||||
|
Collections.singletonList(new SimpleTypeInformationMapper()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultElasticsearchTypeMapper(@Nullable String typeKey, List<? extends TypeInformationMapper> mappers) {
|
||||||
|
this(typeKey, new MapTypeAliasAccessor(typeKey), null, mappers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultElasticsearchTypeMapper(@Nullable String typeKey, TypeAliasAccessor<Map<String, Object>> accessor,
|
||||||
|
@Nullable MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
|
||||||
|
List<? extends TypeInformationMapper> 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<Map<String, Object>> {
|
||||||
|
|
||||||
|
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<String, Object> 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<String, Object> sink, Object alias) {
|
||||||
|
|
||||||
|
if (typeKey == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink.put(typeKey, alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,7 @@ public class ElasticsearchCustomConversions extends CustomConversions {
|
|||||||
static {
|
static {
|
||||||
|
|
||||||
List<Object> converters = new ArrayList<>();
|
List<Object> converters = new ArrayList<>();
|
||||||
|
|
||||||
converters.addAll(GeoConverters.getConvertersToRegister());
|
converters.addAll(GeoConverters.getConvertersToRegister());
|
||||||
converters.add(StringToUUIDConverter.INSTANCE);
|
converters.add(StringToUUIDConverter.INSTANCE);
|
||||||
converters.add(UUIDToStringConverter.INSTANCE);
|
converters.add(UUIDToStringConverter.INSTANCE);
|
||||||
@ -62,6 +63,9 @@ public class ElasticsearchCustomConversions extends CustomConversions {
|
|||||||
super(STORE_CONVERSIONS, converters);
|
super(STORE_CONVERSIONS, converters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to read a {@link UUID} from its {@link String} representation.
|
||||||
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
enum StringToUUIDConverter implements Converter<String, UUID> {
|
enum StringToUUIDConverter implements Converter<String, UUID> {
|
||||||
|
|
||||||
@ -73,6 +77,9 @@ public class ElasticsearchCustomConversions extends CustomConversions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to write a {@link UUID} to its {@link String} representation.
|
||||||
|
*/
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
enum UUIDToStringConverter implements Converter<UUID, String> {
|
enum UUIDToStringConverter implements Converter<UUID, String> {
|
||||||
|
|
||||||
@ -84,6 +91,9 @@ public class ElasticsearchCustomConversions extends CustomConversions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to read a {@link BigDecimal} from a {@link Double} value.
|
||||||
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
enum DoubleToBigDecimalConverter implements Converter<Double, BigDecimal> {
|
enum DoubleToBigDecimalConverter implements Converter<Double, BigDecimal> {
|
||||||
|
|
||||||
@ -95,6 +105,9 @@ public class ElasticsearchCustomConversions extends CustomConversions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to write a {@link BigDecimal} to a {@link Double} value.
|
||||||
|
*/
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
enum BigDecimalToDoubleConverter implements Converter<BigDecimal, Double> {
|
enum BigDecimalToDoubleConverter implements Converter<BigDecimal, Double> {
|
||||||
|
|
||||||
|
@ -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<Map<String, Object>> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,17 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core.convert;
|
package org.springframework.data.elasticsearch.core.convert;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
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.convert.TypeMapper;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
import org.springframework.data.mapping.Alias;
|
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Elasticsearch specific {@link TypeMapper} definition.
|
* Elasticsearch specific {@link TypeMapper} definition.
|
||||||
@ -48,45 +43,15 @@ public interface ElasticsearchTypeMapper extends TypeMapper<Map<String, Object>>
|
|||||||
return readType(source) != null;
|
return readType(source) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ElasticsearchTypeMapper defaultTypeMapper(
|
|
||||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, 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<Map<String, Object>> {
|
static ElasticsearchTypeMapper create(
|
||||||
|
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
|
||||||
private final @Nullable String typeKey;
|
return new DefaultElasticsearchTypeMapper(DEFAULT_TYPE_KEY, mappingContext);
|
||||||
|
|
||||||
public MapTypeAliasAccessor(@Nullable String typeKey) {
|
|
||||||
this.typeKey = typeKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.convert.TypeAliasAccessor#readAliasFrom(java.lang.Object)
|
|
||||||
*/
|
|
||||||
public Alias readAliasFrom(Map<String, Object> 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<String, Object> sink, Object alias) {
|
|
||||||
|
|
||||||
if (typeKey == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sink.put(typeKey, alias);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,14 +35,17 @@ import org.springframework.util.NumberUtils;
|
|||||||
*/
|
*/
|
||||||
class GeoConverters {
|
class GeoConverters {
|
||||||
|
|
||||||
static Collection<? extends Object> getConvertersToRegister() {
|
static Collection<Object> getConvertersToRegister() {
|
||||||
|
|
||||||
return Arrays.asList(PointToMapConverter.INSTANCE, MapToPointConverter.INSTANCE, GeoPointToMapConverter.INSTANCE,
|
return Arrays.asList(PointToMapConverter.INSTANCE, MapToPointConverter.INSTANCE, GeoPointToMapConverter.INSTANCE,
|
||||||
MapToGeoPointConverter.INSTANCE);
|
MapToGeoPointConverter.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to write a {@link Point} to {@link Map} using {@code lat/long} properties.
|
||||||
|
*/
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
enum PointToMapConverter implements Converter<Point, Map> {
|
enum PointToMapConverter implements Converter<Point, Map<String, Object>> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@ -56,8 +59,11 @@ class GeoConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to write a {@link GeoPoint} to {@link Map} using {@code lat/long} properties.
|
||||||
|
*/
|
||||||
@WritingConverter
|
@WritingConverter
|
||||||
enum GeoPointToMapConverter implements Converter<GeoPoint, Map> {
|
enum GeoPointToMapConverter implements Converter<GeoPoint, Map<String, Object>> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@ -70,8 +76,11 @@ class GeoConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to read a {@link Point} from {@link Map} using {@code lat/long} properties.
|
||||||
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
enum MapToPointConverter implements Converter<Map, Point> {
|
enum MapToPointConverter implements Converter<Map<String, Object>, Point> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@ -84,8 +93,11 @@ class GeoConverters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Converter} to read a {@link GeoPoint} from {@link Map} using {@code lat/long} properties.
|
||||||
|
*/
|
||||||
@ReadingConverter
|
@ReadingConverter
|
||||||
enum MapToGeoPointConverter implements Converter<Map, GeoPoint> {
|
enum MapToGeoPointConverter implements Converter<Map<String, Object>, GeoPoint> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.elasticsearch.core;
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
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.SampleMappingEntity;
|
||||||
import org.springframework.data.elasticsearch.entities.UseServerConfigurationEntity;
|
import org.springframework.data.elasticsearch.entities.UseServerConfigurationEntity;
|
||||||
import org.springframework.data.util.CloseableIterator;
|
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
|
* Base for testing rest/transport templates
|
||||||
@ -808,7 +809,7 @@ public class ElasticsearchTemplateTests {
|
|||||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withIndices(INDEX_NAME)
|
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withIndices(INDEX_NAME)
|
||||||
.withTypes(TYPE_NAME).withFields("message").build();
|
.withTypes(TYPE_NAME).withFields("message").build();
|
||||||
// when
|
// when
|
||||||
Page<String> page = elasticsearchTemplate.queryForPage(searchQuery, String.class, new SearchResultMapper() {
|
Page<String> page = elasticsearchTemplate.queryForPage(searchQuery, String.class, new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<String> values = new ArrayList<>();
|
List<String> values = new ArrayList<>();
|
||||||
@ -817,11 +818,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return new AggregatedPageImpl<>((List<T>) values);
|
return new AggregatedPageImpl<>((List<T>) values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// then
|
// then
|
||||||
assertThat(page, is(notNullValue()));
|
assertThat(page, is(notNullValue()));
|
||||||
@ -941,10 +937,10 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final SearchResultMapper searchResultMapper = new SearchResultMapper() {
|
final SearchResultMapper searchResultMapper = new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<SampleEntity> result = new ArrayList<SampleEntity>();
|
List<SampleEntity> result = new ArrayList<>();
|
||||||
for (SearchHit searchHit : response.getHits()) {
|
for (SearchHit searchHit : response.getHits()) {
|
||||||
if (response.getHits().getHits().length <= 0) {
|
if (response.getHits().getHits().length <= 0) {
|
||||||
return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId());
|
return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId());
|
||||||
@ -959,12 +955,7 @@ public class ElasticsearchTemplateTests {
|
|||||||
if (result.size() > 0) {
|
if (result.size() > 0) {
|
||||||
return new AggregatedPageImpl<T>((List<T>) result, response.getScrollId());
|
return new AggregatedPageImpl<T>((List<T>) result, response.getScrollId());
|
||||||
}
|
}
|
||||||
return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId());
|
return new AggregatedPageImpl<T>(Collections.emptyList(), response.getScrollId());
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1347,7 +1338,8 @@ public class ElasticsearchTemplateTests {
|
|||||||
.withHighlightFields(message.toArray(new HighlightBuilder.Field[message.size()]))
|
.withHighlightFields(message.toArray(new HighlightBuilder.Field[message.size()]))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
|
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class,
|
||||||
|
new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<SampleEntity> chunk = new ArrayList<>();
|
List<SampleEntity> chunk = new ArrayList<>();
|
||||||
@ -1366,11 +1358,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage));
|
assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage));
|
||||||
@ -1409,7 +1396,7 @@ public class ElasticsearchTemplateTests {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
|
elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
for (SearchHit searchHit : response.getHits()) {
|
for (SearchHit searchHit : response.getHits()) {
|
||||||
@ -1425,11 +1412,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1458,7 +1440,7 @@ public class ElasticsearchTemplateTests {
|
|||||||
.withHighlightFields(new HighlightBuilder.Field("message"))
|
.withHighlightFields(new HighlightBuilder.Field("message"))
|
||||||
.build();
|
.build();
|
||||||
// when
|
// when
|
||||||
elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
|
elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
for (SearchHit searchHit : response.getHits()) {
|
for (SearchHit searchHit : response.getHits()) {
|
||||||
@ -1471,11 +1453,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1621,7 +1598,8 @@ public class ElasticsearchTemplateTests {
|
|||||||
.withTypes(TYPE_NAME)
|
.withTypes(TYPE_NAME)
|
||||||
.build();
|
.build();
|
||||||
// then
|
// then
|
||||||
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
|
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class,
|
||||||
|
new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<SampleEntity> values = new ArrayList<>();
|
List<SampleEntity> values = new ArrayList<>();
|
||||||
@ -1633,11 +1611,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return new AggregatedPageImpl<>((List<T>) values);
|
return new AggregatedPageImpl<>((List<T>) values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
assertThat(page, is(notNullValue()));
|
assertThat(page, is(notNullValue()));
|
||||||
assertThat(page.getContent().size(), is(1));
|
assertThat(page.getContent().size(), is(1));
|
||||||
@ -1826,7 +1799,8 @@ public class ElasticsearchTemplateTests {
|
|||||||
// then
|
// then
|
||||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices(INDEX_NAME)
|
SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices(INDEX_NAME)
|
||||||
.withTypes(TYPE_NAME).withQuery(matchAllQuery()).build();
|
.withTypes(TYPE_NAME).withQuery(matchAllQuery()).build();
|
||||||
Page<Map> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, Map.class, new SearchResultMapper() {
|
Page<Map> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, Map.class,
|
||||||
|
new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<Map> chunk = new ArrayList<>();
|
List<Map> chunk = new ArrayList<>();
|
||||||
@ -1847,11 +1821,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
assertThat(sampleEntities.getTotalElements(), is(equalTo(2L)));
|
assertThat(sampleEntities.getTotalElements(), is(equalTo(2L)));
|
||||||
assertThat(sampleEntities.getContent().get(0).get("userId"), is(person1.get("userId")));
|
assertThat(sampleEntities.getContent().get(0).get("userId"), is(person1.get("userId")));
|
||||||
@ -2400,7 +2369,8 @@ public class ElasticsearchTemplateTests {
|
|||||||
// When
|
// When
|
||||||
|
|
||||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withTypes("hetro").withIndices(INDEX_1_NAME, INDEX_2_NAME).build();
|
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withTypes("hetro").withIndices(INDEX_1_NAME, INDEX_2_NAME).build();
|
||||||
Page<ResultAggregator> page = elasticsearchTemplate.queryForPage(searchQuery, ResultAggregator.class, new SearchResultMapper() {
|
Page<ResultAggregator> page = elasticsearchTemplate.queryForPage(searchQuery, ResultAggregator.class,
|
||||||
|
new SearchResultMapperAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||||
List<ResultAggregator> values = new ArrayList<>();
|
List<ResultAggregator> values = new ArrayList<>();
|
||||||
@ -2412,11 +2382,6 @@ public class ElasticsearchTemplateTests {
|
|||||||
}
|
}
|
||||||
return new AggregatedPageImpl<>((List<T>) values);
|
return new AggregatedPageImpl<>((List<T>) values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(page.getTotalElements(), is(2l));
|
assertThat(page.getTotalElements(), is(2l));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user