DATAES-530 - Add converter based EntityMapper.
ElasticsearchEntityMapper provides an alternative to the Jackson based EntityMapper implementation. Original Pull Request: #237
This commit is contained in:
@@ -25,12 +25,15 @@ import org.apache.commons.lang.ClassUtils;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchEntityMapper;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.EntityMapper;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
@@ -89,6 +92,13 @@ public class ElasticsearchConfigurationSupportUnitTests {
|
||||
assertThat(context.getBean(ReactiveElasticsearchTemplate.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void usesConfiguredEntityMapper() {
|
||||
|
||||
AbstractApplicationContext context = new AnnotationConfigApplicationContext(EntityMapperConfig.class);
|
||||
assertThat(context.getBean(EntityMapper.class)).isInstanceOf(ElasticsearchEntityMapper.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class StubConfig extends ElasticsearchConfigurationSupport {
|
||||
|
||||
@@ -112,6 +122,21 @@ public class ElasticsearchConfigurationSupportUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class EntityMapperConfig extends ElasticsearchConfigurationSupport {
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public EntityMapper entityMapper() {
|
||||
|
||||
ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(),
|
||||
new DefaultConversionService());
|
||||
entityMapper.setConversions(elasticsearchCustomConversions());
|
||||
|
||||
return entityMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@Document(indexName = "config-support-tests")
|
||||
static class Entity {}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
@@ -38,4 +39,14 @@ public class CustomEntityMapper implements EntityMapper {
|
||||
//mapping text to Object
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> mapObject(Object source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T readObject(Map<String, Object> source, Class<T> targetType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.util.ArrayIterator;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
@@ -36,8 +42,12 @@ import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
@@ -46,11 +56,7 @@ import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMa
|
||||
import org.springframework.data.elasticsearch.entities.Car;
|
||||
import org.springframework.data.elasticsearch.entities.SampleEntity;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import com.fasterxml.jackson.databind.util.ArrayIterator;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
@@ -58,24 +64,43 @@ import static org.mockito.Mockito.*;
|
||||
* @author Chris White
|
||||
* @author Mark Paluch
|
||||
* @author Ilkang Na
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class DefaultResultMapperTests {
|
||||
|
||||
private DefaultResultMapper resultMapper;
|
||||
private SimpleElasticsearchMappingContext context;
|
||||
private EntityMapper entityMapper;
|
||||
|
||||
@Mock
|
||||
private SearchResponse response;
|
||||
@Mock private SearchResponse response;
|
||||
|
||||
public DefaultResultMapperTests(SimpleElasticsearchMappingContext context, EntityMapper entityMapper) {
|
||||
|
||||
this.context = context;
|
||||
this.entityMapper = entityMapper;
|
||||
}
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data() {
|
||||
|
||||
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
|
||||
|
||||
return Arrays.asList(new Object[] { context, new DefaultEntityMapper(context) },
|
||||
new Object[] { context, new ElasticsearchEntityMapper(context, new DefaultConversionService()) });
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
resultMapper = new DefaultResultMapper(new SimpleElasticsearchMappingContext());
|
||||
resultMapper = new DefaultResultMapper(context, entityMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMapAggregationsToPage() {
|
||||
//Given
|
||||
SearchHit[] hits = {createCarHit("Ford", "Grat"), createCarHit("BMW", "Arrow")};
|
||||
// Given
|
||||
SearchHit[] hits = { createCarHit("Ford", "Grat"), createCarHit("BMW", "Arrow") };
|
||||
SearchHits searchHits = mock(SearchHits.class);
|
||||
when(searchHits.getTotalHits()).thenReturn(2L);
|
||||
when(searchHits.iterator()).thenReturn(new ArrayIterator(hits));
|
||||
@@ -84,10 +109,10 @@ public class DefaultResultMapperTests {
|
||||
Aggregations aggregations = new Aggregations(asList(createCarAggregation()));
|
||||
when(response.getAggregations()).thenReturn(aggregations);
|
||||
|
||||
//When
|
||||
// When
|
||||
AggregatedPage<Car> page = (AggregatedPage<Car>) resultMapper.mapResults(response, Car.class, Pageable.unpaged());
|
||||
|
||||
//Then
|
||||
// Then
|
||||
page.hasFacets();
|
||||
assertThat(page.hasAggregations(), is(true));
|
||||
assertThat(page.getAggregation("Diesel").getName(), is("Diesel"));
|
||||
@@ -95,17 +120,17 @@ public class DefaultResultMapperTests {
|
||||
|
||||
@Test
|
||||
public void shouldMapSearchRequestToPage() {
|
||||
//Given
|
||||
SearchHit[] hits = {createCarHit("Ford", "Grat"), createCarHit("BMW", "Arrow")};
|
||||
// Given
|
||||
SearchHit[] hits = { createCarHit("Ford", "Grat"), createCarHit("BMW", "Arrow") };
|
||||
SearchHits searchHits = mock(SearchHits.class);
|
||||
when(searchHits.getTotalHits()).thenReturn(2L);
|
||||
when(searchHits.iterator()).thenReturn(new ArrayIterator(hits));
|
||||
when(response.getHits()).thenReturn(searchHits);
|
||||
|
||||
//When
|
||||
// When
|
||||
Page<Car> page = resultMapper.mapResults(response, Car.class, Pageable.unpaged());
|
||||
|
||||
//Then
|
||||
// Then
|
||||
assertThat(page.hasContent(), is(true));
|
||||
assertThat(page.getTotalElements(), is(2L));
|
||||
assertThat(page.getContent().get(0).getName(), is("Ford"));
|
||||
@@ -113,17 +138,17 @@ public class DefaultResultMapperTests {
|
||||
|
||||
@Test
|
||||
public void shouldMapPartialSearchRequestToObject() {
|
||||
//Given
|
||||
SearchHit[] hits = {createCarPartialHit("Ford", "Grat"), createCarPartialHit("BMW", "Arrow")};
|
||||
// Given
|
||||
SearchHit[] hits = { createCarPartialHit("Ford", "Grat"), createCarPartialHit("BMW", "Arrow") };
|
||||
SearchHits searchHits = mock(SearchHits.class);
|
||||
when(searchHits.getTotalHits()).thenReturn(2L);
|
||||
when(searchHits.iterator()).thenReturn(new ArrayIterator(hits));
|
||||
when(response.getHits()).thenReturn(searchHits);
|
||||
|
||||
//When
|
||||
// When
|
||||
Page<Car> page = resultMapper.mapResults(response, Car.class, Pageable.unpaged());
|
||||
|
||||
//Then
|
||||
// Then
|
||||
assertThat(page.hasContent(), is(true));
|
||||
assertThat(page.getTotalElements(), is(2L));
|
||||
assertThat(page.getContent().get(0).getName(), is("Ford"));
|
||||
@@ -131,14 +156,14 @@ public class DefaultResultMapperTests {
|
||||
|
||||
@Test
|
||||
public void shouldMapGetRequestToObject() {
|
||||
//Given
|
||||
// Given
|
||||
GetResponse response = mock(GetResponse.class);
|
||||
when(response.getSourceAsString()).thenReturn(createJsonCar("Ford", "Grat"));
|
||||
|
||||
//When
|
||||
// When
|
||||
Car result = resultMapper.mapResult(response, Car.class);
|
||||
|
||||
//Then
|
||||
// Then
|
||||
assertThat(result, notNullValue());
|
||||
assertThat(result.getModel(), is("Grat"));
|
||||
assertThat(result.getName(), is("Ford"));
|
||||
|
||||
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
* 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 static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
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.core.convert.ElasticsearchCustomConversions;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.elasticsearch.entities.Car;
|
||||
import org.springframework.data.elasticsearch.entities.GeoEntity;
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class ElasticsearchEntityMapperUnitTests {
|
||||
|
||||
static final String JSON_STRING = "{\"_class\":\"org.springframework.data.elasticsearch.entities.Car\",\"name\":\"Grat\",\"model\":\"Ford\"}";
|
||||
static final String CAR_MODEL = "Ford";
|
||||
static final String CAR_NAME = "Grat";
|
||||
ElasticsearchEntityMapper entityMapper;
|
||||
|
||||
Person sarahConnor;
|
||||
Person kyleReese;
|
||||
Person t800;
|
||||
|
||||
Inventory gun = new Gun("Glock 19", 33);
|
||||
Inventory grenade = new Grenade("40 mm");
|
||||
Inventory rifle = new Rifle("AR-18 Assault Rifle", 3.17, 40);
|
||||
Inventory shotGun = new ShotGun("Ithaca 37 Pump Shotgun");
|
||||
|
||||
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;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
|
||||
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
|
||||
mappingContext.setInitialEntitySet(Collections.singleton(Rifle.class));
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
entityMapper = new ElasticsearchEntityMapper(mappingContext, new GenericConversionService());
|
||||
entityMapper.setConversions(
|
||||
new ElasticsearchCustomConversions(Arrays.asList(new ShotGunToMapConverter(), new MapToShotGunConverter())));
|
||||
entityMapper.afterPropertiesSet();
|
||||
|
||||
sarahConnor = new Person();
|
||||
sarahConnor.id = "sarah";
|
||||
sarahConnor.name = "Sarah Connor";
|
||||
sarahConnor.gender = Gender.MAN;
|
||||
|
||||
kyleReese = new Person();
|
||||
kyleReese.id = "kyle";
|
||||
kyleReese.gender = Gender.MAN;
|
||||
kyleReese.name = "Kyle Reese";
|
||||
|
||||
t800 = new Person();
|
||||
t800.id = "t800";
|
||||
t800.name = "T-800";
|
||||
t800.gender = Gender.MACHINE;
|
||||
|
||||
t800AsMap = new LinkedHashMap<>();
|
||||
t800AsMap.put("id", "t800");
|
||||
t800AsMap.put("name", "T-800");
|
||||
t800AsMap.put("gender", "MACHINE");
|
||||
t800AsMap.put("_class", "org.springframework.data.elasticsearch.core.ElasticsearchEntityMapperUnitTests$Person");
|
||||
|
||||
observatoryRoad = new Address();
|
||||
observatoryRoad.city = "Los Angeles";
|
||||
observatoryRoad.street = "2800 East Observatory Road";
|
||||
observatoryRoad.location = new Point(34.118347D, -118.3026284D);
|
||||
|
||||
bigBunsCafe = new Place();
|
||||
bigBunsCafe.name = "Big Buns Cafe";
|
||||
bigBunsCafe.city = "Los Angeles";
|
||||
bigBunsCafe.street = "15 South Fremont Avenue";
|
||||
bigBunsCafe.location = new Point(34.0945637D, -118.1545845D);
|
||||
|
||||
sarahAsMap = new LinkedHashMap<>();
|
||||
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.put("id", "kyle");
|
||||
kyleAsMap.put("gender", "MAN");
|
||||
kyleAsMap.put("name", "Kyle Reese");
|
||||
|
||||
locationAsMap = new LinkedHashMap<>();
|
||||
locationAsMap.put("lat", 34.118347D);
|
||||
locationAsMap.put("lon", -118.3026284D);
|
||||
|
||||
gratiotAveAsMap = new LinkedHashMap<>();
|
||||
gratiotAveAsMap.put("city", "Los Angeles");
|
||||
gratiotAveAsMap.put("street", "2800 East Observatory Road");
|
||||
gratiotAveAsMap.put("location", locationAsMap);
|
||||
|
||||
bigBunsCafeAsMap = new LinkedHashMap<>();
|
||||
bigBunsCafeAsMap.put("name", "Big Buns Cafe");
|
||||
bigBunsCafeAsMap.put("city", "Los Angeles");
|
||||
bigBunsCafeAsMap.put("street", "15 South Fremont Avenue");
|
||||
bigBunsCafeAsMap.put("location", new LinkedHashMap<>());
|
||||
((HashMap<String, Object>) bigBunsCafeAsMap.get("location")).put("lat", 34.0945637D);
|
||||
((HashMap<String, Object>) bigBunsCafeAsMap.get("location")).put("lon", -118.1545845D);
|
||||
bigBunsCafeAsMap.put("_class",
|
||||
"org.springframework.data.elasticsearch.core.ElasticsearchEntityMapperUnitTests$Place");
|
||||
|
||||
gunAsMap = new LinkedHashMap<>();
|
||||
gunAsMap.put("label", "Glock 19");
|
||||
gunAsMap.put("shotsPerMagazine", 33);
|
||||
gunAsMap.put("_class", Gun.class.getName());
|
||||
|
||||
grenadeAsMap = new LinkedHashMap<>();
|
||||
grenadeAsMap.put("label", "40 mm");
|
||||
grenadeAsMap.put("_class", Grenade.class.getName());
|
||||
|
||||
rifleAsMap = new LinkedHashMap<>();
|
||||
rifleAsMap.put("label", "AR-18 Assault Rifle");
|
||||
rifleAsMap.put("weight", 3.17D);
|
||||
rifleAsMap.put("maxShotsPerMagazine", 40);
|
||||
rifleAsMap.put("_class", "rifle");
|
||||
|
||||
shotGunAsMap = new LinkedHashMap<>();
|
||||
shotGunAsMap.put("model", "Ithaca 37 Pump Shotgun");
|
||||
shotGunAsMap.put("_class", ShotGun.class.getName());
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void shouldMapObjectToJsonString() throws IOException {
|
||||
// Given
|
||||
|
||||
// When
|
||||
String jsonResult = entityMapper.mapToString(Car.builder().model(CAR_MODEL).name(CAR_NAME).build());
|
||||
|
||||
// Then
|
||||
assertThat(jsonResult).isEqualTo(JSON_STRING);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void shouldMapJsonStringToObject() throws IOException {
|
||||
// Given
|
||||
|
||||
// When
|
||||
Car result = entityMapper.mapToObject(JSON_STRING, Car.class);
|
||||
|
||||
// Then
|
||||
assertThat(result.getName()).isEqualTo(CAR_NAME);
|
||||
assertThat(result.getModel()).isEqualTo(CAR_MODEL);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void shouldMapGeoPointElasticsearchNames() throws IOException {
|
||||
// given
|
||||
final Point point = new Point(10, 20);
|
||||
final String pointAsString = point.getX() + "," + point.getY();
|
||||
final double[] pointAsArray = { point.getX(), point.getY() };
|
||||
final GeoEntity geoEntity = GeoEntity.builder().pointA(point).pointB(GeoPoint.fromPoint(point))
|
||||
.pointC(pointAsString).pointD(pointAsArray).build();
|
||||
// when
|
||||
String jsonResult = entityMapper.mapToString(geoEntity);
|
||||
|
||||
// then
|
||||
assertThat(jsonResult).contains(pointTemplate("pointA", point));
|
||||
assertThat(jsonResult).contains(pointTemplate("pointB", point));
|
||||
assertThat(jsonResult).contains(String.format(Locale.ENGLISH, "\"%s\":\"%s\"", "pointC", pointAsString));
|
||||
assertThat(jsonResult)
|
||||
.contains(String.format(Locale.ENGLISH, "\"%s\":[%.1f,%.1f]", "pointD", pointAsArray[0], pointAsArray[1]));
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void ignoresReadOnlyProperties() throws IOException {
|
||||
|
||||
// given
|
||||
Sample sample = new Sample();
|
||||
sample.readOnly = "readOnly";
|
||||
sample.property = "property";
|
||||
sample.javaTransientProperty = "javaTransient";
|
||||
sample.annotatedTransientProperty = "transient";
|
||||
|
||||
// when
|
||||
String result = entityMapper.mapToString(sample);
|
||||
|
||||
// then
|
||||
assertThat(result).contains("\"property\"");
|
||||
assertThat(result).contains("\"javaTransient\"");
|
||||
|
||||
assertThat(result).doesNotContain("readOnly");
|
||||
assertThat(result).doesNotContain("annotatedTransientProperty");
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writesNestedEntity() {
|
||||
|
||||
Person person = new Person();
|
||||
person.birthdate = new Date();
|
||||
person.gender = Gender.MAN;
|
||||
person.address = observatoryRoad;
|
||||
|
||||
LinkedHashMap<String, Object> sink = writeToMap(person);
|
||||
|
||||
assertThat(sink.get("address")).isEqualTo(gratiotAveAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writesConcreteList() throws IOException {
|
||||
|
||||
Person ginger = new Person();
|
||||
ginger.id = "ginger";
|
||||
ginger.gender = Gender.MAN;
|
||||
|
||||
sarahConnor.coWorkers = Arrays.asList(kyleReese, ginger);
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(sarahConnor);
|
||||
assertThat((List) target.get("coWorkers")).hasSize(2).contains(kyleAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writesInterfaceList() throws IOException {
|
||||
|
||||
Inventory gun = new Gun("Glock 19", 33);
|
||||
Inventory grenade = new Grenade("40 mm");
|
||||
|
||||
sarahConnor.inventoryList = Arrays.asList(gun, grenade);
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(sarahConnor);
|
||||
assertThat((List) target.get("inventoryList")).containsExactly(gunAsMap, grenadeAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readTypeCorrectly() {
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target).isEqualTo(sarahConnor);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readListOfConcreteTypesCorrectly() {
|
||||
|
||||
sarahAsMap.put("coWorkers", Arrays.asList(kyleAsMap));
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target.getCoWorkers()).contains(kyleReese);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readListOfInterfacesTypesCorrectly() {
|
||||
|
||||
sarahAsMap.put("inventoryList", Arrays.asList(gunAsMap, grenadeAsMap));
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target.getInventoryList()).containsExactly(gun, grenade);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writeMapOfConcreteType() {
|
||||
|
||||
sarahConnor.shippingAddresses = new LinkedHashMap<>();
|
||||
sarahConnor.shippingAddresses.put("home", observatoryRoad);
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(sarahConnor);
|
||||
assertThat(target.get("shippingAddresses")).isInstanceOf(Map.class);
|
||||
assertThat(target.get("shippingAddresses")).isEqualTo(Collections.singletonMap("home", gratiotAveAsMap));
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writeMapOfInterfaceType() {
|
||||
|
||||
sarahConnor.inventoryMap = new LinkedHashMap<>();
|
||||
sarahConnor.inventoryMap.put("glock19", gun);
|
||||
sarahConnor.inventoryMap.put("40 mm grenade", grenade);
|
||||
|
||||
LinkedHashMap<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);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readConcreteMapCorrectly() {
|
||||
|
||||
sarahAsMap.put("shippingAddresses", Collections.singletonMap("home", gratiotAveAsMap));
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target.getShippingAddresses()).hasSize(1).containsEntry("home", observatoryRoad);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readInterfaceMapCorrectly() {
|
||||
|
||||
sarahAsMap.put("inventoryMap", Collections.singletonMap("glock19", gunAsMap));
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target.getInventoryMap()).hasSize(1).containsEntry("glock19", gun);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void genericWriteList() {
|
||||
|
||||
Skynet skynet = new Skynet();
|
||||
skynet.objectList = new ArrayList<>();
|
||||
skynet.objectList.add(t800);
|
||||
skynet.objectList.add(gun);
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(skynet);
|
||||
|
||||
assertThat((List<Object>) target.get("objectList")).containsExactly(t800AsMap, gunAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readGenericList() {
|
||||
|
||||
LinkedHashMap<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("objectList", Arrays.asList(t800AsMap, gunAsMap));
|
||||
|
||||
Skynet target = entityMapper.read(Skynet.class, source);
|
||||
|
||||
assertThat(target.getObjectList()).containsExactly(t800, gun);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void genericWriteListWithList() {
|
||||
|
||||
Skynet skynet = new Skynet();
|
||||
skynet.objectList = new ArrayList<>();
|
||||
skynet.objectList.add(Arrays.asList(t800, gun));
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(skynet);
|
||||
|
||||
assertThat((List<Object>) target.get("objectList")).containsExactly(Arrays.asList(t800AsMap, gunAsMap));
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readGenericListList() {
|
||||
|
||||
LinkedHashMap<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("objectList", Arrays.asList(Arrays.asList(t800AsMap, gunAsMap)));
|
||||
|
||||
Skynet target = entityMapper.read(Skynet.class, source);
|
||||
|
||||
assertThat(target.getObjectList()).containsExactly(Arrays.asList(t800, gun));
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writeGenericMap() {
|
||||
|
||||
Skynet skynet = new Skynet();
|
||||
skynet.objectMap = new LinkedHashMap<>();
|
||||
skynet.objectMap.put("gun", gun);
|
||||
skynet.objectMap.put("grenade", grenade);
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(skynet);
|
||||
|
||||
assertThat((Map<String, Object>) target.get("objectMap")).containsEntry("gun", gunAsMap).containsEntry("grenade",
|
||||
grenadeAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readGenericMap() {
|
||||
|
||||
LinkedHashMap<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("objectMap", Collections.singletonMap("glock19", gunAsMap));
|
||||
|
||||
Skynet target = entityMapper.read(Skynet.class, source);
|
||||
|
||||
assertThat(target.getObjectMap()).containsEntry("glock19", gun);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writeGenericMapMap() {
|
||||
|
||||
Skynet skynet = new Skynet();
|
||||
skynet.objectMap = new LinkedHashMap<>();
|
||||
skynet.objectMap.put("inventory", Collections.singletonMap("glock19", gun));
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(skynet);
|
||||
|
||||
assertThat((Map<String, Object>) target.get("objectMap")).containsEntry("inventory",
|
||||
Collections.singletonMap("glock19", gunAsMap));
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readGenericMapMap() {
|
||||
|
||||
LinkedHashMap<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("objectMap", Collections.singletonMap("inventory", Collections.singletonMap("glock19", gunAsMap)));
|
||||
|
||||
Skynet target = entityMapper.read(Skynet.class, source);
|
||||
|
||||
assertThat(target.getObjectMap()).containsEntry("inventory", Collections.singletonMap("glock19", gun));
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readsNestedEntity() {
|
||||
|
||||
sarahAsMap.put("address", gratiotAveAsMap);
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target.getAddress()).isEqualTo(observatoryRoad);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readsNestedObjectEntity() {
|
||||
|
||||
LinkedHashMap<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("object", t800AsMap);
|
||||
|
||||
Skynet target = entityMapper.read(Skynet.class, source);
|
||||
|
||||
assertThat(target.getObject()).isEqualTo(t800);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writesAliased() {
|
||||
assertThat(writeToMap(rifle)).containsEntry("_class", "rifle").doesNotContainValue(Rifle.class.getName());
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writesNestedAliased() {
|
||||
|
||||
t800.inventoryList = Collections.singletonList(rifle);
|
||||
LinkedHashMap<String, Object> target = writeToMap(t800);
|
||||
|
||||
assertThat((List) target.get("inventoryList")).contains(rifleAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readsAliased() {
|
||||
assertThat(entityMapper.read(Inventory.class, rifleAsMap)).isEqualTo(rifle);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readsNestedAliased() {
|
||||
|
||||
t800AsMap.put("inventoryList", Collections.singletonList(rifleAsMap));
|
||||
|
||||
assertThat(entityMapper.read(Person.class, t800AsMap).getInventoryList()).containsExactly(rifle);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void appliesCustomConverterForWrite() {
|
||||
assertThat(writeToMap(shotGun)).isEqualTo(shotGunAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void appliesCustomConverterForRead() {
|
||||
assertThat(entityMapper.read(Inventory.class, shotGunAsMap)).isEqualTo(shotGun);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void writeSubTypeCorrectly() {
|
||||
|
||||
sarahConnor.address = bigBunsCafe;
|
||||
|
||||
LinkedHashMap<String, Object> target = writeToMap(sarahConnor);
|
||||
|
||||
assertThat(target.get("address")).isEqualTo(bigBunsCafeAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-530
|
||||
public void readSubTypeCorrectly() {
|
||||
|
||||
sarahAsMap.put("address", bigBunsCafeAsMap);
|
||||
|
||||
Person target = entityMapper.read(Person.class, sarahAsMap);
|
||||
|
||||
assertThat(target.address).isEqualTo(bigBunsCafe);
|
||||
}
|
||||
|
||||
private String pointTemplate(String name, Point point) {
|
||||
return String.format(Locale.ENGLISH, "\"%s\":{\"lat\":%.1f,\"lon\":%.1f}", name, point.getX(), point.getY());
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, Object> writeToMap(Object source) {
|
||||
|
||||
LinkedHashMap<String, Object> sink = new LinkedHashMap<>();
|
||||
entityMapper.write(source, sink);
|
||||
return sink;
|
||||
}
|
||||
|
||||
public static class Sample {
|
||||
|
||||
public @ReadOnlyProperty String readOnly;
|
||||
public @Transient String annotatedTransientProperty;
|
||||
public transient String javaTransientProperty;
|
||||
public String property;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Person {
|
||||
|
||||
@Id String id;
|
||||
String name;
|
||||
Date birthdate;
|
||||
Gender gender;
|
||||
Address address;
|
||||
|
||||
List<Person> coWorkers;
|
||||
List<Inventory> inventoryList;
|
||||
Map<String, Address> shippingAddresses;
|
||||
Map<String, Inventory> inventoryMap;
|
||||
}
|
||||
|
||||
enum Gender {
|
||||
|
||||
MAN("1"), MACHINE("0");
|
||||
|
||||
String theValue;
|
||||
|
||||
Gender(String theValue) {
|
||||
this.theValue = theValue;
|
||||
}
|
||||
|
||||
public String getTheValue() {
|
||||
return theValue;
|
||||
}
|
||||
}
|
||||
|
||||
interface Inventory {
|
||||
|
||||
String getLabel();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
static class Gun implements Inventory {
|
||||
|
||||
final String label;
|
||||
final int shotsPerMagazine;
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
static class Grenade implements Inventory {
|
||||
|
||||
final String label;
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
@TypeAlias("rifle")
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
static class Rifle implements Inventory {
|
||||
|
||||
final String label;
|
||||
final double weight;
|
||||
final int maxShotsPerMagazine;
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
static class ShotGun implements Inventory {
|
||||
|
||||
final String label;
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Address {
|
||||
|
||||
Point location;
|
||||
String street;
|
||||
String city;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Place extends Address {
|
||||
|
||||
String name;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Skynet {
|
||||
|
||||
Object object;
|
||||
List<Object> objectList;
|
||||
Map<String, Object> objectMap;
|
||||
}
|
||||
|
||||
@WritingConverter
|
||||
static class ShotGunToMapConverter implements Converter<ShotGun, Map<String, Object>> {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> convert(ShotGun source) {
|
||||
|
||||
LinkedHashMap<String, Object> target = new LinkedHashMap<>();
|
||||
target.put("model", source.getLabel());
|
||||
target.put("_class", ShotGun.class.getName());
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
static class MapToShotGunConverter implements Converter<Map<String, Object>, ShotGun> {
|
||||
|
||||
@Override
|
||||
public ShotGun convert(Map<String, Object> source) {
|
||||
return new ShotGun(source.get("model").toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -817,6 +817,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return new AggregatedPageImpl<>((List<T>) values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
// then
|
||||
assertThat(page, is(notNullValue()));
|
||||
@@ -956,6 +961,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1356,6 +1366,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage));
|
||||
@@ -1410,6 +1425,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1451,6 +1471,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1491,6 +1516,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1603,6 +1633,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return new AggregatedPageImpl<>((List<T>) values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
assertThat(page, is(notNullValue()));
|
||||
assertThat(page.getContent().size(), is(1));
|
||||
@@ -1812,6 +1847,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
assertThat(sampleEntities.getTotalElements(), is(equalTo(2L)));
|
||||
assertThat(sampleEntities.getContent().get(0).get("userId"), is(person1.get("userId")));
|
||||
@@ -2372,6 +2412,11 @@ public class ElasticsearchTemplateTests {
|
||||
}
|
||||
return new AggregatedPageImpl<>((List<T>) values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(page.getTotalElements(), is(2l));
|
||||
|
||||
@@ -101,7 +101,7 @@ public class MappingBuilderTests {
|
||||
assertThat(xContentBuilderToString(xContentBuilder), is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // DATAES-530
|
||||
public void shouldAddStockPriceDocumentToIndex() throws IOException {
|
||||
// Given
|
||||
|
||||
@@ -112,8 +112,9 @@ public class MappingBuilderTests {
|
||||
String symbol = "AU";
|
||||
double price = 2.34;
|
||||
String id = "abc";
|
||||
|
||||
elasticsearchTemplate
|
||||
.index(buildIndex(StockPrice.builder().id(id).symbol(symbol).price(new BigDecimal(price)).build()));
|
||||
.index(buildIndex(StockPrice.builder().id(id).symbol(symbol).price(BigDecimal.valueOf(price)).build()));
|
||||
elasticsearchTemplate.refresh(StockPrice.class);
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
|
||||
@@ -122,7 +123,7 @@ public class MappingBuilderTests {
|
||||
assertThat(result.size(), is(1));
|
||||
StockPrice entry = result.get(0);
|
||||
assertThat(entry.getSymbol(), is(symbol));
|
||||
assertThat(entry.getPrice(), is(new BigDecimal(price)));
|
||||
assertThat(entry.getPrice(), is(BigDecimal.valueOf(price)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
@@ -86,7 +87,9 @@ public class ReactiveElasticsearchTemplateTests {
|
||||
restTemplate.putMapping(SampleEntity.class);
|
||||
restTemplate.refresh(SampleEntity.class);
|
||||
|
||||
template = new ReactiveElasticsearchTemplate(TestUtils.reactiveClient());
|
||||
template = new ReactiveElasticsearchTemplate(TestUtils.reactiveClient(), restTemplate.getElasticsearchConverter(),
|
||||
new DefaultResultMapper(new ElasticsearchEntityMapper(
|
||||
restTemplate.getElasticsearchConverter().getMappingContext(), new DefaultConversionService())));
|
||||
}
|
||||
|
||||
@Test // DATAES-504
|
||||
|
||||
Reference in New Issue
Block a user