Skip to content

Commit 7ae55b9

Browse files
authored
Add custom property converters.
Original Pull Request #1953 Closes #1945
1 parent 464fc31 commit 7ae55b9

18 files changed

+358
-125
lines changed

Diff for: src/main/asciidoc/reference/elasticsearch-migration-guide-4.2-4.3.adoc

+5
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,8 @@ Spring Data Elasticsearch now uses `org.springframework.data.elasticsearch.core.
7171
=== Completion classes
7272

7373
The classes from the package `org.springframework.data.elasticsearch.core.completion` have been moved to `org.springframework.data.elasticsearch.core.suggest`.
74+
75+
=== Other renamings
76+
77+
The `org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter` interface has been renamed to `org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter`.
78+
Likewise the implementations classes named _XXPersistentPropertyConverter_ have been renamed to _XXPropertyValueConverter_.

Diff for: src/main/asciidoc/reference/elasticsearch-object-mapping.adoc

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ This means, that no mapping entry is written for the property and that Elasticse
5656
** `analyzer`, `searchAnalyzer`, `normalizer` for specifying custom analyzers and normalizer.
5757
* `@GeoPoint`: Marks a field as _geo_point_ datatype.
5858
Can be omitted if the field is an instance of the `GeoPoint` class.
59+
* `@ValueConverter` defines a class to be used to convert the given property.
60+
In difference to a registered Spring `Converter` this only converts the annotated property and not every property of the given type.
5961

6062
The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic.
6163

@@ -184,6 +186,7 @@ public class Person { <1>
184186
"lastname" : "Connor"
185187
}
186188
----
189+
187190
<1> By default the domain types class name is used for the type hint.
188191
====
189192

@@ -211,6 +214,7 @@ public class Person {
211214
"id" : ...
212215
}
213216
----
217+
214218
<1> The configured alias is used when writing the entity.
215219
====
216220

@@ -421,6 +425,7 @@ public class Config extends AbstractElasticsearchConfiguration {
421425
"localidad" : { "lat" : 34.118347, "lon" : -118.3026284 }
422426
}
423427
----
428+
424429
<1> Add `Converter` implementations.
425430
<2> Set up the `Converter` used for writing `DomainType` to Elasticsearch.
426431
<3> Set up the `Converter` used for reading `DomainType` from search result.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.annotations;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Inherited;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
26+
27+
/**
28+
* Annotation to put on a property of an entity to define a value converter which can convert the property to a type
29+
* that Elasticsearch understands and back.
30+
*
31+
* @author Peter-Josef Meisch
32+
* @since 4.3
33+
*/
34+
@Retention(RetentionPolicy.RUNTIME)
35+
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
36+
@Documented
37+
@Inherited
38+
public @interface ValueConverter {
39+
40+
/**
41+
* Defines the class implementing the {@link PropertyValueConverter} interface. If this is a normal class, it must
42+
* provide a default constructor with no arguments. If this is an enum and thus implementing a singleton by enum it
43+
* must only have one enum value.
44+
*
45+
* @return the class to use for conversion
46+
*/
47+
Class<? extends PropertyValueConverter> value();
48+
}

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractPersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractPropertyValueConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@
1515
*/
1616
package org.springframework.data.elasticsearch.core.convert;
1717

18-
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter;
18+
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
1919
import org.springframework.data.mapping.PersistentProperty;
2020
import org.springframework.util.Assert;
2121

2222
/**
2323
* @author Sascha Woo
2424
* @since 4.3
2525
*/
26-
public abstract class AbstractPersistentPropertyConverter implements ElasticsearchPersistentPropertyConverter {
26+
public abstract class AbstractPropertyValueConverter implements PropertyValueConverter {
2727

2828
private final PersistentProperty<?> property;
2929

30-
public AbstractPersistentPropertyConverter(PersistentProperty<?> property) {
30+
public AbstractPropertyValueConverter(PersistentProperty<?> property) {
3131

3232
Assert.notNull(property, "property must not be null.");
3333
this.property = property;

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePropertyValueConverter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
* @author Sascha Woo
2727
* @since 4.3
2828
*/
29-
public abstract class AbstractRangePersistentPropertyConverter<T> extends AbstractPersistentPropertyConverter {
29+
public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPropertyValueConverter {
3030

3131
protected static final String LT_FIELD = "lt";
3232
protected static final String LTE_FIELD = "lte";
3333
protected static final String GT_FIELD = "gt";
3434
protected static final String GTE_FIELD = "gte";
3535

36-
public AbstractRangePersistentPropertyConverter(PersistentProperty<?> property) {
36+
public AbstractRangePropertyValueConverter(PersistentProperty<?> property) {
3737
super(property);
3838
}
3939

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/DatePersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/DatePropertyValueConverter.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,13 @@
2626
* @author Sascha Woo
2727
* @since 4.3
2828
*/
29-
public class DatePersistentPropertyConverter extends AbstractPersistentPropertyConverter {
29+
public class DatePropertyValueConverter extends AbstractPropertyValueConverter {
3030

31-
private static final Logger LOGGER = LoggerFactory.getLogger(DatePersistentPropertyConverter.class);
31+
private static final Logger LOGGER = LoggerFactory.getLogger(DatePropertyValueConverter.class);
3232

3333
private final List<ElasticsearchDateConverter> dateConverters;
3434

35-
public DatePersistentPropertyConverter(PersistentProperty<?> property,
36-
List<ElasticsearchDateConverter> dateConverters) {
35+
public DatePropertyValueConverter(PersistentProperty<?> property, List<ElasticsearchDateConverter> dateConverters) {
3736

3837
super(property);
3938
this.dateConverters = dateConverters;

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/DateRangePersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/DateRangePropertyValueConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
* @author Sascha Woo
2727
* @since 4.3
2828
*/
29-
public class DateRangePersistentPropertyConverter extends AbstractRangePersistentPropertyConverter<Date> {
29+
public class DateRangePropertyValueConverter extends AbstractRangePropertyValueConverter<Date> {
3030

31-
private static final Logger LOGGER = LoggerFactory.getLogger(DateRangePersistentPropertyConverter.class);
31+
private static final Logger LOGGER = LoggerFactory.getLogger(DateRangePropertyValueConverter.class);
3232

3333
private final List<ElasticsearchDateConverter> dateConverters;
3434

35-
public DateRangePersistentPropertyConverter(PersistentProperty<?> property,
35+
public DateRangePropertyValueConverter(PersistentProperty<?> property,
3636
List<ElasticsearchDateConverter> dateConverters) {
3737

3838
super(property);

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchConverter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.data.elasticsearch.core.document.Document;
2020
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
2121
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
22+
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
2223
import org.springframework.data.elasticsearch.core.query.Query;
2324
import org.springframework.data.projection.ProjectionFactory;
2425
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
@@ -93,8 +94,7 @@ default Document mapObject(@Nullable Object source) {
9394
/**
9495
* Updates a {@link Query} by renaming the property names in the query to the correct mapped field names and the
9596
* values to the converted values if the {@link ElasticsearchPersistentProperty} for a property has a
96-
* {@link org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter}. If
97-
* domainClass is null it's a noop.
97+
* {@link PropertyValueConverter}. If domainClass is null it's a noop.
9898
*
9999
* @param query the query that is internally updated, must not be {@literal null}
100100
* @param domainClass the class of the object that is searched with the query

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java

+21-21
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import org.springframework.data.elasticsearch.core.document.SearchDocument;
4040
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
4141
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
42-
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentPropertyConverter;
42+
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
4343
import org.springframework.data.elasticsearch.core.query.Criteria;
4444
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
4545
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
@@ -425,8 +425,9 @@ protected <R> R readValue(@Nullable Object value, ElasticsearchPersistentPropert
425425

426426
Class<?> rawType = type.getType();
427427

428-
if (property.hasPropertyConverter()) {
429-
value = propertyConverterRead(property, value);
428+
if (property.hasPropertyValueConverter()) {
429+
// noinspection unchecked
430+
return (R) propertyConverterRead(property, value);
430431
} else if (TemporalAccessor.class.isAssignableFrom(property.getType())
431432
&& !conversions.hasCustomReadTarget(value.getClass(), rawType)) {
432433

@@ -466,27 +467,27 @@ private <T> T readValue(Object value, TypeInformation<?> type) {
466467
}
467468

468469
private Object propertyConverterRead(ElasticsearchPersistentProperty property, Object source) {
469-
ElasticsearchPersistentPropertyConverter propertyConverter = Objects
470-
.requireNonNull(property.getPropertyConverter());
470+
PropertyValueConverter propertyValueConverter = Objects.requireNonNull(property.getPropertyValueConverter());
471471

472472
if (source instanceof String[]) {
473473
// convert to a List
474474
source = Arrays.asList((String[]) source);
475475
}
476476

477477
if (source instanceof List) {
478-
source = ((List<?>) source).stream().map(it -> convertOnRead(propertyConverter, it))
478+
source = ((List<?>) source).stream().map(it -> convertOnRead(propertyValueConverter, it))
479479
.collect(Collectors.toList());
480480
} else if (source instanceof Set) {
481-
source = ((Set<?>) source).stream().map(it -> convertOnRead(propertyConverter, it)).collect(Collectors.toSet());
481+
source = ((Set<?>) source).stream().map(it -> convertOnRead(propertyValueConverter, it))
482+
.collect(Collectors.toSet());
482483
} else {
483-
source = convertOnRead(propertyConverter, source);
484+
source = convertOnRead(propertyValueConverter, source);
484485
}
485486
return source;
486487
}
487488

488-
private Object convertOnRead(ElasticsearchPersistentPropertyConverter propertyConverter, Object source) {
489-
return propertyConverter.read(source);
489+
private Object convertOnRead(PropertyValueConverter propertyValueConverter, Object source) {
490+
return propertyValueConverter.read(source);
490491
}
491492

492493
/**
@@ -897,7 +898,7 @@ private void writeProperties(ElasticsearchPersistentEntity<?> entity, Persistent
897898
continue;
898899
}
899900

900-
if (property.hasPropertyConverter()) {
901+
if (property.hasPropertyValueConverter()) {
901902
value = propertyConverterWrite(property, value);
902903
sink.set(property, value);
903904
} else if (TemporalAccessor.class.isAssignableFrom(property.getActualType())
@@ -1070,15 +1071,14 @@ private Object getPotentiallyConvertedSimpleWrite(@Nullable Object value, @Nulla
10701071
}
10711072

10721073
private Object propertyConverterWrite(ElasticsearchPersistentProperty property, Object value) {
1073-
ElasticsearchPersistentPropertyConverter propertyConverter = Objects
1074-
.requireNonNull(property.getPropertyConverter());
1074+
PropertyValueConverter propertyValueConverter = Objects.requireNonNull(property.getPropertyValueConverter());
10751075

10761076
if (value instanceof List) {
1077-
value = ((List<?>) value).stream().map(propertyConverter::write).collect(Collectors.toList());
1077+
value = ((List<?>) value).stream().map(propertyValueConverter::write).collect(Collectors.toList());
10781078
} else if (value instanceof Set) {
1079-
value = ((Set<?>) value).stream().map(propertyConverter::write).collect(Collectors.toSet());
1079+
value = ((Set<?>) value).stream().map(propertyValueConverter::write).collect(Collectors.toSet());
10801080
} else {
1081-
value = propertyConverter.write(value);
1081+
value = propertyValueConverter.write(value);
10821082
}
10831083
return value;
10841084
}
@@ -1252,18 +1252,18 @@ private void updateCriteria(Criteria criteria, ElasticsearchPersistentEntity<?>
12521252

12531253
if (persistentProperty != null) {
12541254

1255-
if (persistentProperty.hasPropertyConverter()) {
1256-
ElasticsearchPersistentPropertyConverter propertyConverter = Objects
1257-
.requireNonNull(persistentProperty.getPropertyConverter());
1255+
if (persistentProperty.hasPropertyValueConverter()) {
1256+
PropertyValueConverter propertyValueConverter = Objects
1257+
.requireNonNull(persistentProperty.getPropertyValueConverter());
12581258
criteria.getQueryCriteriaEntries().forEach(criteriaEntry -> {
12591259
Object value = criteriaEntry.getValue();
12601260
if (value.getClass().isArray()) {
12611261
Object[] objects = (Object[]) value;
12621262
for (int i = 0; i < objects.length; i++) {
1263-
objects[i] = propertyConverter.write(objects[i]);
1263+
objects[i] = propertyValueConverter.write(objects[i]);
12641264
}
12651265
} else {
1266-
criteriaEntry.setValue(propertyConverter.write(value));
1266+
criteriaEntry.setValue(propertyValueConverter.write(value));
12671267
}
12681268
});
12691269
}

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/NumberRangePersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/NumberRangePropertyValueConverter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
* @author Sascha Woo
2222
* @since 4.3
2323
*/
24-
public class NumberRangePersistentPropertyConverter extends AbstractRangePersistentPropertyConverter<Number> {
24+
public class NumberRangePropertyValueConverter extends AbstractRangePropertyValueConverter<Number> {
2525

26-
public NumberRangePersistentPropertyConverter(PersistentProperty<?> property) {
26+
public NumberRangePropertyValueConverter(PersistentProperty<?> property) {
2727
super(property);
2828
}
2929

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalPersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalPropertyValueConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
* @author Sascha Woo
2727
* @since 4.3
2828
*/
29-
public class TemporalPersistentPropertyConverter extends AbstractPersistentPropertyConverter {
29+
public class TemporalPropertyValueConverter extends AbstractPropertyValueConverter {
3030

31-
private static final Logger LOGGER = LoggerFactory.getLogger(TemporalPersistentPropertyConverter.class);
31+
private static final Logger LOGGER = LoggerFactory.getLogger(TemporalPropertyValueConverter.class);
3232

3333
private final List<ElasticsearchDateConverter> dateConverters;
3434

35-
public TemporalPersistentPropertyConverter(PersistentProperty<?> property,
35+
public TemporalPropertyValueConverter(PersistentProperty<?> property,
3636
List<ElasticsearchDateConverter> dateConverters) {
3737

3838
super(property);

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalRangePersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalRangePropertyValueConverter.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,13 @@
2727
* @author Sascha Woo
2828
* @since 4.3
2929
*/
30-
public class TemporalRangePersistentPropertyConverter
31-
extends AbstractRangePersistentPropertyConverter<TemporalAccessor> {
30+
public class TemporalRangePropertyValueConverter extends AbstractRangePropertyValueConverter<TemporalAccessor> {
3231

33-
private static final Logger LOGGER = LoggerFactory.getLogger(TemporalRangePersistentPropertyConverter.class);
32+
private static final Logger LOGGER = LoggerFactory.getLogger(TemporalRangePropertyValueConverter.class);
3433

3534
private final List<ElasticsearchDateConverter> dateConverters;
3635

37-
public TemporalRangePersistentPropertyConverter(PersistentProperty<?> property,
36+
public TemporalRangePropertyValueConverter(PersistentProperty<?> property,
3837
List<ElasticsearchDateConverter> dateConverters) {
3938

4039
super(property);

Diff for: src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentProperty.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,17 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
4848
boolean isSeqNoPrimaryTermProperty();
4949

5050
/**
51-
* @return true if an {@link ElasticsearchPersistentPropertyConverter} is available for this instance.
51+
* @return true if an {@link PropertyValueConverter} is available for this instance.
5252
* @since 4.0
5353
*/
54-
boolean hasPropertyConverter();
54+
boolean hasPropertyValueConverter();
5555

5656
/**
57-
* @return the {@link ElasticsearchPersistentPropertyConverter} for this instance.
57+
* @return the {@link PropertyValueConverter} for this instance.
5858
* @since 4.0
5959
*/
6060
@Nullable
61-
ElasticsearchPersistentPropertyConverter getPropertyConverter();
61+
PropertyValueConverter getPropertyValueConverter();
6262

6363
/**
6464
* Returns true if the property may be read.

Diff for: src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentPropertyConverter.java renamed to src/main/java/org/springframework/data/elasticsearch/core/mapping/PropertyValueConverter.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,26 @@
1616
package org.springframework.data.elasticsearch.core.mapping;
1717

1818
/**
19-
* Interface defining methods to convert a persistent property value to an elasticsearch property value and back.
19+
* Interface defining methods to convert the value of an entity-property to a value in Elasticsearch and back.
2020
*
2121
* @author Peter-Josef Meisch
2222
* @author Sascha Woo
2323
*/
24-
public interface ElasticsearchPersistentPropertyConverter {
24+
public interface PropertyValueConverter {
2525

2626
/**
27-
* Converts a persistent property value to an elasticsearch property value.
27+
* Converts a property value to an elasticsearch value.
2828
*
29-
* @param value the persistent property value to convert, must not be {@literal null}
30-
* @return The elasticsearch property value.
29+
* @param value the value to convert, must not be {@literal null}
30+
* @return The elasticsearch property value, must not be {@literal null}
3131
*/
3232
Object write(Object value);
3333

3434
/**
35-
* Converts an elasticsearch property value to a persistent property value.
35+
* Converts an elasticsearch property value to a property value.
3636
*
3737
* @param value the elasticsearch property value to convert, must not be {@literal null}
38-
* @return The persistent property value.
38+
* @return The converted value, must not be {@literal null}
3939
*/
4040
Object read(Object value);
4141
}

0 commit comments

Comments
 (0)