mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-24 13:02:10 +00:00
Fix mapping of property values into a collection.
When reading from Elasticsearch into a property of type Collection<T> (List<T> or Set<T>) the MappingElasticsearchConverter now can read both from the returned JSON: an array of T objects - will put the objects in a corresponding collection a single T object will put the single object into a corrsponding colletcion This is implemented and tested for both: entities where the properties have setters and immutable classes that only provide an all-args constructor. Original Pull Request #2282 Closes #2280
This commit is contained in:
parent
8377f64a8a
commit
86634ceb38
@ -201,7 +201,7 @@ public class MappingElasticsearchConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to do the actual writing. The methods originally were in the MappingElasticsearchConverter class, but are
|
* Class to do the actual reading. The methods originally were in the MappingElasticsearchConverter class, but are
|
||||||
* refactored to allow for keeping state during the conversion of an object.
|
* refactored to allow for keeping state during the conversion of an object.
|
||||||
*/
|
*/
|
||||||
private static class Reader extends Base {
|
private static class Reader extends Base {
|
||||||
@ -220,10 +220,17 @@ public class MappingElasticsearchConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
/**
|
||||||
|
* Reads the given source into the given type.
|
||||||
|
*
|
||||||
|
* @param type they type to convert the given source to.
|
||||||
|
* @param source the source to create an object of the given type from.
|
||||||
|
* @return the object that was read
|
||||||
|
*/
|
||||||
<R> R read(Class<R> type, Document source) {
|
<R> R read(Class<R> type, Document source) {
|
||||||
|
|
||||||
TypeInformation<R> typeHint = TypeInformation.of((Class<R>) ClassUtils.getUserClass(type));
|
TypeInformation<R> typeInformation = TypeInformation.of((Class<R>) ClassUtils.getUserClass(type));
|
||||||
R r = read(typeHint, source);
|
R r = read(typeInformation, source);
|
||||||
|
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
throw new ConversionException("could not convert into object of class " + type);
|
throw new ConversionException("could not convert into object of class " + type);
|
||||||
@ -234,11 +241,11 @@ public class MappingElasticsearchConverter
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <R> R read(TypeInformation<R> type, Map<String, Object> source) {
|
private <R> R read(TypeInformation<R> typeInformation, Map<String, Object> source) {
|
||||||
|
|
||||||
Assert.notNull(source, "Source must not be null!");
|
Assert.notNull(source, "Source must not be null!");
|
||||||
|
|
||||||
TypeInformation<? extends R> typeToUse = typeMapper.readType(source, type);
|
TypeInformation<? extends R> typeToUse = typeMapper.readType(source, typeInformation);
|
||||||
Class<? extends R> rawType = typeToUse.getType();
|
Class<? extends R> rawType = typeToUse.getType();
|
||||||
|
|
||||||
if (conversions.hasCustomReadTarget(source.getClass(), rawType)) {
|
if (conversions.hasCustomReadTarget(source.getClass(), rawType)) {
|
||||||
@ -256,8 +263,8 @@ public class MappingElasticsearchConverter
|
|||||||
if (typeToUse.equals(TypeInformation.OBJECT)) {
|
if (typeToUse.equals(TypeInformation.OBJECT)) {
|
||||||
return (R) source;
|
return (R) source;
|
||||||
}
|
}
|
||||||
// Retrieve persistent entity info
|
|
||||||
|
|
||||||
|
// Retrieve persistent entity info
|
||||||
ElasticsearchPersistentEntity<?> entity = mappingContext.getPersistentEntity(typeToUse);
|
ElasticsearchPersistentEntity<?> entity = mappingContext.getPersistentEntity(typeToUse);
|
||||||
|
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
@ -372,7 +379,6 @@ public class MappingElasticsearchConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParameterValueProvider<ElasticsearchPersistentProperty> getParameterProvider(
|
private ParameterValueProvider<ElasticsearchPersistentProperty> getParameterProvider(
|
||||||
@ -462,12 +468,44 @@ public class MappingElasticsearchConverter
|
|||||||
} else if (value.getClass().isArray()) {
|
} else if (value.getClass().isArray()) {
|
||||||
return (T) readCollectionOrArray(type, Arrays.asList((Object[]) value));
|
return (T) readCollectionOrArray(type, Arrays.asList((Object[]) value));
|
||||||
} else if (value instanceof Map) {
|
} else if (value instanceof Map) {
|
||||||
|
|
||||||
|
TypeInformation<?> collectionComponentType = getCollectionComponentType(type);
|
||||||
|
if (collectionComponentType != null) {
|
||||||
|
Object o = read(collectionComponentType, (Map<String, Object>) value);
|
||||||
|
return getCollectionWithSingleElement(type, collectionComponentType, o);
|
||||||
|
}
|
||||||
return (T) read(type, (Map<String, Object>) value);
|
return (T) read(type, (Map<String, Object>) value);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
TypeInformation<?> collectionComponentType = getCollectionComponentType(type);
|
||||||
|
if (collectionComponentType != null
|
||||||
|
&& collectionComponentType.isAssignableFrom(TypeInformation.of(value.getClass()))) {
|
||||||
|
Object o = getPotentiallyConvertedSimpleRead(value, collectionComponentType);
|
||||||
|
return getCollectionWithSingleElement(type, collectionComponentType, o);
|
||||||
|
}
|
||||||
|
|
||||||
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> T getCollectionWithSingleElement(TypeInformation<?> collectionType,
|
||||||
|
TypeInformation<?> componentType, Object element) {
|
||||||
|
Collection<Object> collection = CollectionFactory.createCollection(collectionType.getType(),
|
||||||
|
componentType.getType(), 1);
|
||||||
|
collection.add(element);
|
||||||
|
return (T) collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type the type to check
|
||||||
|
* @return true if type is a collectoin, null otherwise,
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
TypeInformation<?> getCollectionComponentType(TypeInformation<?> type) {
|
||||||
|
return type.isCollectionLike() ? type.getComponentType() : null;
|
||||||
|
}
|
||||||
|
|
||||||
private Object propertyConverterRead(ElasticsearchPersistentProperty property, Object source) {
|
private Object propertyConverterRead(ElasticsearchPersistentProperty property, Object source) {
|
||||||
PropertyValueConverter propertyValueConverter = Objects.requireNonNull(property.getPropertyValueConverter());
|
PropertyValueConverter propertyValueConverter = Objects.requireNonNull(property.getPropertyValueConverter());
|
||||||
|
|
||||||
@ -1148,17 +1186,18 @@ public class MappingElasticsearchConverter
|
|||||||
|
|
||||||
Assert.notNull(query, "query must not be null");
|
Assert.notNull(query, "query must not be null");
|
||||||
|
|
||||||
if (domainClass != null) {
|
if (domainClass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateFieldsAndSourceFilter(query, domainClass);
|
updatePropertiesInFieldsAndSourceFilter(query, domainClass);
|
||||||
|
|
||||||
if (query instanceof CriteriaQuery) {
|
if (query instanceof CriteriaQuery) {
|
||||||
updateCriteriaQuery((CriteriaQuery) query, domainClass);
|
updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
||||||
|
|
||||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
|
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
|
||||||
|
|
||||||
@ -1196,14 +1235,22 @@ public class MappingElasticsearchConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> updateFieldNames(List<String> fields, ElasticsearchPersistentEntity<?> persistentEntity) {
|
/**
|
||||||
return fields.stream().map(fieldName -> {
|
* relaces the fieldName with the property name of a property of the persistentEntity with the corresponding
|
||||||
|
* fieldname. If no such property exists, the original fieldName is kept.
|
||||||
|
*
|
||||||
|
* @param fieldNames list of fieldnames
|
||||||
|
* @param persistentEntity the persistent entity to check
|
||||||
|
* @return an updated list of field names
|
||||||
|
*/
|
||||||
|
private List<String> updateFieldNames(List<String> fieldNames, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||||
|
return fieldNames.stream().map(fieldName -> {
|
||||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(fieldName);
|
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(fieldName);
|
||||||
return persistentProperty != null ? persistentProperty.getFieldName() : fieldName;
|
return persistentProperty != null ? persistentProperty.getFieldName() : fieldName;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
|
private void updatePropertiesInCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
|
||||||
|
|
||||||
Assert.notNull(criteriaQuery, "criteriaQuery must not be null");
|
Assert.notNull(criteriaQuery, "criteriaQuery must not be null");
|
||||||
Assert.notNull(domainClass, "domainClass must not be null");
|
Assert.notNull(domainClass, "domainClass must not be null");
|
||||||
@ -1212,17 +1259,17 @@ public class MappingElasticsearchConverter
|
|||||||
|
|
||||||
if (persistentEntity != null) {
|
if (persistentEntity != null) {
|
||||||
for (Criteria chainedCriteria : criteriaQuery.getCriteria().getCriteriaChain()) {
|
for (Criteria chainedCriteria : criteriaQuery.getCriteria().getCriteriaChain()) {
|
||||||
updateCriteria(chainedCriteria, persistentEntity);
|
updatePropertiesInCriteria(chainedCriteria, persistentEntity);
|
||||||
}
|
}
|
||||||
for (Criteria subCriteria : criteriaQuery.getCriteria().getSubCriteria()) {
|
for (Criteria subCriteria : criteriaQuery.getCriteria().getSubCriteria()) {
|
||||||
for (Criteria chainedCriteria : subCriteria.getCriteriaChain()) {
|
for (Criteria chainedCriteria : subCriteria.getCriteriaChain()) {
|
||||||
updateCriteria(chainedCriteria, persistentEntity);
|
updatePropertiesInCriteria(chainedCriteria, persistentEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCriteria(Criteria criteria, ElasticsearchPersistentEntity<?> persistentEntity) {
|
private void updatePropertiesInCriteria(Criteria criteria, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||||
|
|
||||||
Field field = criteria.getField();
|
Field field = criteria.getField();
|
||||||
|
|
||||||
|
@ -34,7 +34,10 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
@ -1531,6 +1534,336 @@ public class MappingElasticsearchConverterUnitTests {
|
|||||||
mappingElasticsearchConverter.updateQuery(query, EntityWithCustomValueConverters.class);
|
mappingElasticsearchConverter.updateQuery(query, EntityWithCustomValueConverters.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single String into a List property")
|
||||||
|
void shouldReadASingleStringIntoAListProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringList": "foo"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringList()).containsExactly("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a String array into a List property")
|
||||||
|
void shouldReadAStringArrayIntoAListProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringList": ["foo", "bar"]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringList()).containsExactly("foo", "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single String into a Set property")
|
||||||
|
void shouldReadASingleStringIntoASetProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringSet": "foo"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringSet()).containsExactly("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a String array into a Set property")
|
||||||
|
void shouldReadAStringArrayIntoASetProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringSet": ["foo", "bar"]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringSet()).containsExactly("foo", "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single object into a List property")
|
||||||
|
void shouldReadASingleObjectIntoAListProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenList": {
|
||||||
|
"name": "child"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenList()).hasSize(1);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read an object array into a List property")
|
||||||
|
void shouldReadAnObjectArrayIntoAListProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenList": [
|
||||||
|
{
|
||||||
|
"name": "child1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "child2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenList()).hasSize(2);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child1");
|
||||||
|
assertThat(entity.getChildrenList().get(1).getName()).isEqualTo("child2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single object into a Set property")
|
||||||
|
void shouldReadASingleObjectIntoASetProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenSet": {
|
||||||
|
"name": "child"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenSet()).hasSize(1);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
assertThat(entity.getChildrenSet().iterator().next().getName()).isEqualTo("child");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read an object array into a Set property")
|
||||||
|
void shouldReadAnObjectArrayIntoASetProperty() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenSet": [
|
||||||
|
{
|
||||||
|
"name": "child1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "child2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenSet()).hasSize(2);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
List<String> names = entity.getChildrenSet().stream().map(EntityWithCollections.Child::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertThat(names).containsExactlyInAnyOrder("child1", "child2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single String into a List property immutable")
|
||||||
|
void shouldReadASingleStringIntoAListPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringList": "foo"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringList()).containsExactly("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a String array into a List property immutable")
|
||||||
|
void shouldReadAStringArrayIntoAListPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringList": ["foo", "bar"]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringList()).containsExactly("foo", "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single String into a Set property immutable")
|
||||||
|
void shouldReadASingleStringIntoASetPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringSet": "foo"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringSet()).containsExactly("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a String array into a Set property immutable")
|
||||||
|
void shouldReadAStringArrayIntoASetPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"stringSet": ["foo", "bar"]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getStringSet()).containsExactly("foo", "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single object into a List property immutable")
|
||||||
|
void shouldReadASingleObjectIntoAListPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenList": {
|
||||||
|
"name": "child"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenList()).hasSize(1);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read an object array into a List property immutable")
|
||||||
|
void shouldReadAnObjectArrayIntoAListPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenList": [
|
||||||
|
{
|
||||||
|
"name": "child1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "child2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenList()).hasSize(2);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child1");
|
||||||
|
assertThat(entity.getChildrenList().get(1).getName()).isEqualTo("child2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read a single object into a Set property immutable")
|
||||||
|
void shouldReadASingleObjectIntoASetPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenSet": {
|
||||||
|
"name": "child"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenSet()).hasSize(1);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
assertThat(entity.getChildrenSet().iterator().next().getName()).isEqualTo("child");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // #2280
|
||||||
|
@DisplayName("should read an object array into a Set property immutable")
|
||||||
|
void shouldReadAnObjectArrayIntoASetPropertyImmutable() {
|
||||||
|
|
||||||
|
@Language("JSON")
|
||||||
|
var json = """
|
||||||
|
{
|
||||||
|
"childrenSet": [
|
||||||
|
{
|
||||||
|
"name": "child1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "child2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
Document source = Document.parse(json);
|
||||||
|
|
||||||
|
var entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class, source);
|
||||||
|
|
||||||
|
assertThat(entity.getChildrenSet()).hasSize(2);
|
||||||
|
// noinspection ConstantConditions
|
||||||
|
List<String> names = entity.getChildrenSet().stream().map(ImmutableEntityWithCollections.Child::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertThat(names).containsExactlyInAnyOrder("child1", "child2");
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> writeToMap(Object source) {
|
private Map<String, Object> writeToMap(Object source) {
|
||||||
|
|
||||||
Document sink = Document.create();
|
Document sink = Document.create();
|
||||||
@ -2472,6 +2805,128 @@ public class MappingElasticsearchConverterUnitTests {
|
|||||||
return reverse(value);
|
return reverse(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class EntityWithCollections {
|
||||||
|
@Field(type = FieldType.Keyword)
|
||||||
|
@Nullable private List<String> stringList;
|
||||||
|
|
||||||
|
@Field(type = FieldType.Keyword)
|
||||||
|
@Nullable private Set<String> stringSet;
|
||||||
|
|
||||||
|
@Field(type = FieldType.Object)
|
||||||
|
@Nullable private List<Child> childrenList;
|
||||||
|
|
||||||
|
@Field(type = FieldType.Object)
|
||||||
|
@Nullable private Set<Child> childrenSet;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public List<String> getStringList() {
|
||||||
|
return stringList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStringList(@Nullable List<String> stringList) {
|
||||||
|
this.stringList = stringList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Set<String> getStringSet() {
|
||||||
|
return stringSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStringSet(@Nullable Set<String> stringSet) {
|
||||||
|
this.stringSet = stringSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public List<Child> getChildrenList() {
|
||||||
|
return childrenList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildrenList(@Nullable List<Child> childrenList) {
|
||||||
|
this.childrenList = childrenList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Set<Child> getChildrenSet() {
|
||||||
|
return childrenSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildrenSet(@Nullable Set<Child> childrenSet) {
|
||||||
|
this.childrenSet = childrenSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Child {
|
||||||
|
|
||||||
|
@Field(type = FieldType.Keyword)
|
||||||
|
@Nullable private String name;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ImmutableEntityWithCollections {
|
||||||
|
@Field(type = FieldType.Keyword)
|
||||||
|
@Nullable private List<String> stringList;
|
||||||
|
|
||||||
|
@Field(type = FieldType.Keyword)
|
||||||
|
@Nullable private Set<String> stringSet;
|
||||||
|
|
||||||
|
@Field(type = FieldType.Object)
|
||||||
|
@Nullable private List<Child> childrenList;
|
||||||
|
|
||||||
|
@Field(type = FieldType.Object)
|
||||||
|
@Nullable private Set<Child> childrenSet;
|
||||||
|
|
||||||
|
public ImmutableEntityWithCollections(@Nullable List<String> stringList, @Nullable Set<String> stringSet,
|
||||||
|
@Nullable List<Child> childrenList, @Nullable Set<Child> childrenSet) {
|
||||||
|
this.stringList = stringList;
|
||||||
|
this.stringSet = stringSet;
|
||||||
|
this.childrenList = childrenList;
|
||||||
|
this.childrenSet = childrenSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public List<String> getStringList() {
|
||||||
|
return stringList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Set<String> getStringSet() {
|
||||||
|
return stringSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public List<Child> getChildrenList() {
|
||||||
|
return childrenList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Set<Child> getChildrenSet() {
|
||||||
|
return childrenSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Child {
|
||||||
|
|
||||||
|
@Field(type = FieldType.Keyword)
|
||||||
|
@Nullable private String name;
|
||||||
|
|
||||||
|
public Child(@Nullable String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
private static String reverse(Object o) {
|
private static String reverse(Object o) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user