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