Skip to content

Commit 2284315

Browse files
christophstroblmp911de
authored andcommitted
Refine API and property-converter documentation.
See #1484 Original pull request: #2566.
1 parent e729227 commit 2284315

20 files changed

+1061
-310
lines changed

src/main/java/org/springframework/data/convert/CustomConversions.java

+33-11
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,16 @@
1616
package org.springframework.data.convert;
1717

1818
import java.lang.annotation.Annotation;
19-
import java.util.*;
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.Collection;
22+
import java.util.Collections;
23+
import java.util.HashSet;
24+
import java.util.LinkedHashSet;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.Optional;
28+
import java.util.Set;
2029
import java.util.concurrent.ConcurrentHashMap;
2130
import java.util.function.Function;
2231
import java.util.function.Predicate;
@@ -33,7 +42,6 @@
3342
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
3443
import org.springframework.core.convert.support.GenericConversionService;
3544
import org.springframework.data.convert.ConverterBuilder.ConverterAware;
36-
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
3745
import org.springframework.data.mapping.PersistentProperty;
3846
import org.springframework.data.mapping.model.SimpleTypeHolder;
3947
import org.springframework.data.util.Predicates;
@@ -98,7 +106,7 @@ public class CustomConversions {
98106
private final Function<ConvertiblePair, Class<?>> getRawWriteTarget = convertiblePair -> getCustomTarget(
99107
convertiblePair.getSourceType(), null, writingPairs);
100108

101-
private PropertyValueConversions propertyValueConversions;
109+
private @Nullable PropertyValueConversions propertyValueConversions;
102110

103111
/**
104112
* @param converterConfiguration the {@link ConverterConfiguration} to apply.
@@ -182,7 +190,7 @@ public void registerConvertersIn(ConverterRegistry conversionService) {
182190
* @param property must not be {@literal null}.
183191
* @return {@literal true} if a specific {@link PropertyValueConverter} is available.
184192
* @see PropertyValueConversions#hasValueConverter(PersistentProperty)
185-
* @since ?
193+
* @since 2.7
186194
*/
187195
public boolean hasPropertyValueConverter(PersistentProperty<?> property) {
188196
return propertyValueConversions != null ? propertyValueConversions.hasValueConverter(property) : false;
@@ -197,11 +205,11 @@ public boolean hasPropertyValueConverter(PersistentProperty<?> property) {
197205
* @param <C> conversion context type
198206
* @return the suitable {@link PropertyValueConverter} or {@literal null} if none available.
199207
* @see PropertyValueConversions#getValueConverter(PersistentProperty)
200-
* @since ?
208+
* @since 2.7
201209
*/
202210
@Nullable
203-
public <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getPropertyValueConverter(
204-
PersistentProperty<?> property) {
211+
public <A, B, C extends PersistentProperty<C>, D extends ValueConversionContext<C>> PropertyValueConverter<A, B, D> getPropertyValueConverter(
212+
C property) {
205213
return propertyValueConversions != null ? propertyValueConversions.getValueConverter(property) : null;
206214
}
207215

@@ -326,8 +334,8 @@ private boolean isSupportedConverter(ConverterRegistrationIntent registrationInt
326334
registrationIntent.getSourceType(), registrationIntent.getTargetType(),
327335
registrationIntent.isReading() ? "reading" : "writing"));
328336
} else {
329-
logger.debug(String.format(SKIP_CONVERTER, registrationIntent.getSourceType(), registrationIntent.getTargetType(),
330-
registrationIntent.isReading() ? "reading" : "writing",
337+
logger.debug(String.format(SKIP_CONVERTER, registrationIntent.getSourceType(),
338+
registrationIntent.getTargetType(), registrationIntent.isReading() ? "reading" : "writing",
331339
registrationIntent.isReading() ? registrationIntent.getSourceType() : registrationIntent.getTargetType()));
332340
}
333341
}
@@ -926,8 +934,22 @@ public ConverterConfiguration(StoreConversions storeConversions, List<?> userCon
926934
this(storeConversions, userConverters, converterRegistrationFilter, new SimplePropertyValueConversions());
927935
}
928936

937+
/**
938+
* Create a new ConverterConfiguration holding the given {@link StoreConversions} and user defined converters as
939+
* well as a {@link Collection} of {@link ConvertiblePair} for which to skip the registration of default converters.
940+
* <br />
941+
* This allows store implementations to modify default converter registration based on specific needs and
942+
* configurations. User defined converters will are never subject of filtering.
943+
*
944+
* @param storeConversions must not be {@literal null}.
945+
* @param userConverters must not be {@literal null} use {@link Collections#emptyList()} instead.
946+
* @param converterRegistrationFilter must not be {@literal null}.
947+
* @param propertyValueConversions can be {@literal null}.
948+
* @since 2.7
949+
*/
929950
public ConverterConfiguration(StoreConversions storeConversions, List<?> userConverters,
930-
Predicate<ConvertiblePair> converterRegistrationFilter, @Nullable PropertyValueConversions propertyValueConversions) {
951+
Predicate<ConvertiblePair> converterRegistrationFilter,
952+
@Nullable PropertyValueConversions propertyValueConversions) {
931953

932954
this.storeConversions = storeConversions;
933955
this.userConverters = new ArrayList<>(userConverters);
@@ -958,7 +980,7 @@ boolean shouldRegister(ConvertiblePair candidate) {
958980

959981
/**
960982
* @return the configured {@link PropertyValueConversions} if set, {@literal null} otherwise.
961-
* @since ?
983+
* @since 2.7
962984
*/
963985
@Nullable
964986
public PropertyValueConversions getPropertyValueConversions() {

src/main/java/org/springframework/data/convert/PropertyValueConversions.java

+22-7
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@
1515
*/
1616
package org.springframework.data.convert;
1717

18-
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
18+
import java.util.function.Consumer;
19+
1920
import org.springframework.data.mapping.PersistentProperty;
2021
import org.springframework.lang.Nullable;
2122

2223
/**
2324
* {@link PropertyValueConversions} provides access to {@link PropertyValueConverter converters} that may only be
2425
* applied to a specific property. Other than {@link org.springframework.core.convert.converter.Converter converters}
25-
* registered in {@link CustomConversions} the property based variants accept and allow returning {@literal null} values
26-
* and provide access to a store specific {@link PropertyValueConverter.ValueConversionContext conversion context}.
26+
* registered in {@link CustomConversions}, the property based variants accept and allow returning {@literal null}
27+
* values and provide access to a store specific {@link ValueConversionContext conversion context}.
2728
*
2829
* @author Christoph Strobl
29-
* @since ?
30+
* @since 2.7
3031
* @currentBook The Desert Prince - Peter V. Brett
3132
*/
3233
public interface PropertyValueConversions {
@@ -38,7 +39,7 @@ public interface PropertyValueConversions {
3839
* @return {@literal true} if a specific {@link PropertyValueConverter} is available.
3940
*/
4041
default boolean hasValueConverter(PersistentProperty<?> property) {
41-
return getValueConverter(property) != null;
42+
return getValueConverter((PersistentProperty) property) != null;
4243
}
4344

4445
/**
@@ -50,6 +51,20 @@ default boolean hasValueConverter(PersistentProperty<?> property) {
5051
* @return the suitable {@link PropertyValueConverter} or {@literal null} if none available.
5152
*/
5253
@Nullable
53-
<A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getValueConverter(
54-
PersistentProperty<?> property);
54+
<A, B, C extends PersistentProperty<C>, D extends ValueConversionContext<C>> PropertyValueConverter<A, B, D> getValueConverter(
55+
C property);
56+
57+
/**
58+
* Helper that allows to create {@link PropertyValueConversions} instance with the configured
59+
* {@link PropertyValueConverter converters} provided via the given callback.
60+
*/
61+
static <P extends PersistentProperty<P>> PropertyValueConversions simple(
62+
Consumer<PropertyValueConverterRegistrar<P>> config) {
63+
64+
SimplePropertyValueConversions conversions = new SimplePropertyValueConversions();
65+
PropertyValueConverterRegistrar registrar = new PropertyValueConverterRegistrar();
66+
config.accept(registrar);
67+
conversions.setValueConverterRegistry(registrar.buildRegistry());
68+
return conversions;
69+
}
5570
}

src/main/java/org/springframework/data/convert/PropertyValueConverter.java

+37-92
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
*/
1616
package org.springframework.data.convert;
1717

18-
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
18+
import java.util.function.BiFunction;
19+
1920
import org.springframework.data.mapping.PersistentProperty;
20-
import org.springframework.data.util.ClassTypeInformation;
21-
import org.springframework.data.util.TypeInformation;
2221
import org.springframework.lang.Nullable;
2322

2423
/**
@@ -29,8 +28,9 @@
2928
* to special annotated fields which allows a fine grained conversion of certain values within a specific context.
3029
*
3130
* @author Christoph Strobl
32-
* @param <A> domain specific type
33-
* @param <B> store native type
31+
* @param <A> domain specific type.
32+
* @param <B> store native type.
33+
* @param <C> the store specific {@link ValueConversionContext conversion context}.
3434
* @since 2.7
3535
*/
3636
public interface PropertyValueConverter<A, B, C extends ValueConversionContext<? extends PersistentProperty<?>>> {
@@ -39,126 +39,71 @@ public interface PropertyValueConverter<A, B, C extends ValueConversionContext<?
3939
* Convert the given store specific value into it's domain value representation. Typically a {@literal read}
4040
* operation.
4141
*
42-
* @param nativeValue can be {@literal null}.
42+
* @param value can be {@literal null}.
4343
* @param context never {@literal null}.
4444
* @return the converted value. Can be {@literal null}.
4545
*/
4646
@Nullable
47-
A /*read*/ nativeToDomain(@Nullable B nativeValue, C context);
47+
A read(@Nullable B value, C context);
4848

4949
/**
5050
* Convert the given domain specific value into it's native store representation. Typically a {@literal write}
5151
* operation.
5252
*
53-
* @param domainValue can be {@literal null}.
53+
* @param value can be {@literal null}.
5454
* @param context never {@literal null}.
5555
* @return the converted value. Can be {@literal null}.
5656
*/
5757
@Nullable
58-
B /*write*/ domainToNative(@Nullable A domainValue, C context);
58+
B write(@Nullable A value, C context);
5959

6060
/**
61+
* NoOp {@link PropertyValueConverter} implementation.
62+
*
6163
* @author Christoph Strobl
62-
* @author Oliver Drotbohm
6364
*/
64-
interface ValueConversionContext<P extends PersistentProperty<P>> {
65-
66-
/**
67-
* Return the {@link PersistentProperty} to be handled.
68-
*
69-
* @return will never be {@literal null}.
70-
*/
71-
P getProperty();
72-
73-
/**
74-
* Write to whatever type is considered best for the given source.
75-
*
76-
* @param value
77-
* @return
78-
*/
79-
@Nullable
80-
default Object write(@Nullable Object value) {
81-
return null;
82-
}
83-
84-
/**
85-
* Write as the given type.
86-
*
87-
* @param value can be {@literal null}.
88-
* @param target must not be {@literal null}.
89-
* @return can be {@literal null}.
90-
*/
91-
@Nullable
92-
default <T> T write(@Nullable Object value, Class<T> target) {
93-
return write(value, ClassTypeInformation.from(target));
94-
}
95-
96-
/**
97-
* Write as the given type.
98-
*
99-
* @param value can be {@literal null}.
100-
* @param target must not be {@literal null}.
101-
* @return can be {@literal null}.
102-
*/
103-
@Nullable
104-
default <T> T write(@Nullable Object value, TypeInformation<T> target) {
105-
return null;
106-
}
65+
@SuppressWarnings({ "rawtypes", "null" })
66+
enum ObjectToObjectPropertyValueConverter implements PropertyValueConverter {
10767

108-
/**
109-
* Reads the value into the type of the current property.
110-
*
111-
* @param value can be {@literal null}.
112-
* @return can be {@literal null}.
113-
*/
114-
@Nullable
115-
default Object read(@Nullable Object value) {
116-
return read(value, getProperty().getTypeInformation());
117-
}
68+
INSTANCE;
11869

119-
/**
120-
* Reads the value as the given type.
121-
*
122-
* @param value can be {@literal null}.
123-
* @param target must not be {@literal null}.
124-
* @return can be {@literal null}.
125-
*/
126-
@Nullable
127-
default <T> T read(@Nullable Object value, Class<T> target) {
128-
return null;
70+
@Override
71+
public Object read(Object value, ValueConversionContext context) {
72+
return value;
12973
}
13074

131-
/**
132-
* Reads the value as the given type.
133-
*
134-
* @param value can be {@literal null}.
135-
* @param target must not be {@literal null}.
136-
* @return can be {@literal null}.
137-
*/
138-
@Nullable
139-
default <T> T read(@Nullable Object value, TypeInformation<T> target) {
140-
return null;
75+
@Override
76+
public Object write(Object value, ValueConversionContext context) {
77+
return value;
14178
}
14279
}
14380

14481
/**
145-
* NoOp {@link PropertyValueConverter} implementation.
82+
* A {@link PropertyValueConverter} that delegates conversion to the given {@link BiFunction}s.
14683
*
147-
* @author Christoph Strobl
84+
* @author Oliver Drotbohm
14885
*/
149-
@SuppressWarnings({ "rawtypes", "null" })
150-
enum ObjectToObjectPropertyValueConverter implements PropertyValueConverter {
86+
class FunctionPropertyValueConverter<A, B, P extends PersistentProperty<P>>
87+
implements PropertyValueConverter<A, B, ValueConversionContext<P>> {
15188

152-
INSTANCE;
89+
private final BiFunction<A, ValueConversionContext<P>, B> writer;
90+
private final BiFunction<B, ValueConversionContext<P>, A> reader;
91+
92+
public FunctionPropertyValueConverter(BiFunction<A, ValueConversionContext<P>, B> writer,
93+
BiFunction<B, ValueConversionContext<P>, A> reader) {
94+
95+
this.writer = writer;
96+
this.reader = reader;
97+
}
15398

15499
@Override
155-
public Object nativeToDomain(Object value, ValueConversionContext context) {
156-
return value;
100+
public B write(A value, ValueConversionContext<P> context) {
101+
return writer.apply(value, context);
157102
}
158103

159104
@Override
160-
public Object domainToNative(Object value, ValueConversionContext context) {
161-
return value;
105+
public A read(B value, ValueConversionContext<P> context) {
106+
return reader.apply(value, context);
162107
}
163108
}
164109
}

0 commit comments

Comments
 (0)