Skip to content

Commit dda102a

Browse files
committed
Polishing.
Increase visibility of converter builders. Refine generics naming towards DV/SV instead of A/B to easier identify store-native values and domains-specific values in the API. Refactor PropertyValueConversions.hasValueConverter into a non-default method. Tweak documentation. See #1484 Original pull request: #2566.
1 parent 2284315 commit dda102a

17 files changed

+156
-381
lines changed

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
* Value object to capture custom conversion. That is essentially a {@link List} of converters and some additional logic
5656
* around them. The converters build up two sets of types which store-specific basic types can be converted into and
5757
* from. These types will be considered simple ones (which means they neither need deeper inspection nor nested
58-
* conversion. Thus the {@link CustomConversions} also act as factory for {@link SimpleTypeHolder} .
58+
* conversion. Thus, the {@link CustomConversions} also act as factory for {@link SimpleTypeHolder} .
5959
*
6060
* @author Oliver Gierke
6161
* @author Thomas Darimont
@@ -193,22 +193,23 @@ public void registerConvertersIn(ConverterRegistry conversionService) {
193193
* @since 2.7
194194
*/
195195
public boolean hasPropertyValueConverter(PersistentProperty<?> property) {
196-
return propertyValueConversions != null ? propertyValueConversions.hasValueConverter(property) : false;
196+
return propertyValueConversions != null && propertyValueConversions.hasValueConverter(property);
197197
}
198198

199199
/**
200200
* Delegate to obtain the {@link PropertyValueConverter} for the given {@literal property} from
201201
* {@link PropertyValueConversions}.
202202
*
203-
* @param property must not be {@literal null}. param <A> domain specific type
204-
* @param <B> store native type
203+
* @param property must not be {@literal null}.
204+
* @param <DV> domain-specific type
205+
* @param <SV> store-native type
205206
* @param <C> conversion context type
206207
* @return the suitable {@link PropertyValueConverter} or {@literal null} if none available.
207208
* @see PropertyValueConversions#getValueConverter(PersistentProperty)
208209
* @since 2.7
209210
*/
210211
@Nullable
211-
public <A, B, C extends PersistentProperty<C>, D extends ValueConversionContext<C>> PropertyValueConverter<A, B, D> getPropertyValueConverter(
212+
public <DV, SV, C extends PersistentProperty<C>, VCC extends ValueConversionContext<C>> PropertyValueConverter<DV, SV, VCC> getPropertyValueConverter(
212213
C property) {
213214
return propertyValueConversions != null ? propertyValueConversions.getValueConverter(property) : null;
214215
}

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

+8-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import java.util.function.Consumer;
1919

2020
import org.springframework.data.mapping.PersistentProperty;
21-
import org.springframework.lang.Nullable;
2221

2322
/**
2423
* {@link PropertyValueConversions} provides access to {@link PropertyValueConverter converters} that may only be
@@ -38,26 +37,25 @@ public interface PropertyValueConversions {
3837
* @param property must not be {@literal null}.
3938
* @return {@literal true} if a specific {@link PropertyValueConverter} is available.
4039
*/
41-
default boolean hasValueConverter(PersistentProperty<?> property) {
42-
return getValueConverter((PersistentProperty) property) != null;
43-
}
40+
boolean hasValueConverter(PersistentProperty<?> property);
4441

4542
/**
46-
* Get the {@link PropertyValueConverter} for the given {@literal property} if present.
43+
* Get the {@link PropertyValueConverter} for the given {@literal property}.
4744
*
48-
* @param property must not be {@literal null}. param <A> domain specific type
49-
* @param <B> store native type
45+
* @param property must not be {@literal null}.
46+
* @param <DV> domain-specific type
47+
* @param <SV> store-native type
5048
* @param <C> conversion context type
51-
* @return the suitable {@link PropertyValueConverter} or {@literal null} if none available.
49+
* @return the suitable {@link PropertyValueConverter}.
5250
*/
53-
@Nullable
54-
<A, B, C extends PersistentProperty<C>, D extends ValueConversionContext<C>> PropertyValueConverter<A, B, D> getValueConverter(
51+
<DV, SV, C extends PersistentProperty<C>, VCC extends ValueConversionContext<C>> PropertyValueConverter<DV, SV, VCC> getValueConverter(
5552
C property);
5653

5754
/**
5855
* Helper that allows to create {@link PropertyValueConversions} instance with the configured
5956
* {@link PropertyValueConverter converters} provided via the given callback.
6057
*/
58+
@SuppressWarnings({ "rawtypes", "unchecked" })
6159
static <P extends PersistentProperty<P>> PropertyValueConversions simple(
6260
Consumer<PropertyValueConverterRegistrar<P>> config) {
6361

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

+25-21
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,44 @@
2121
import org.springframework.lang.Nullable;
2222

2323
/**
24-
* {@link PropertyValueConverter} provides a symmetric way of converting certain properties from domain to store
25-
* specific values.
24+
* {@link PropertyValueConverter} provides a symmetric way of converting certain properties from domain to
25+
* store-specific values.
2626
* <p>
2727
* A {@link PropertyValueConverter} is, other than a {@link ReadingConverter} or {@link WritingConverter}, only applied
28-
* to special annotated fields which allows a fine grained conversion of certain values within a specific context.
28+
* to special annotated fields which allows a fine-grained conversion of certain values within a specific context.
2929
*
3030
* @author Christoph Strobl
31-
* @param <A> domain specific type.
32-
* @param <B> store native type.
31+
* @param <DV> domain-specific type.
32+
* @param <SV> store-native type.
3333
* @param <C> the store specific {@link ValueConversionContext conversion context}.
3434
* @since 2.7
3535
*/
36-
public interface PropertyValueConverter<A, B, C extends ValueConversionContext<? extends PersistentProperty<?>>> {
36+
public interface PropertyValueConverter<DV, SV, C extends ValueConversionContext<? extends PersistentProperty<?>>> {
3737

3838
/**
39-
* Convert the given store specific value into it's domain value representation. Typically a {@literal read}
39+
* Convert the given store specific value into it's domain value representation. Typically, a {@literal read}
4040
* operation.
4141
*
4242
* @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(@Nullable B value, C context);
47+
DV read(@Nullable SV value, C context);
4848

4949
/**
50-
* Convert the given domain specific value into it's native store representation. Typically a {@literal write}
50+
* Convert the given domain-specific value into it's native store representation. Typically, a {@literal write}
5151
* operation.
5252
*
5353
* @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(@Nullable A value, C context);
58+
SV write(@Nullable DV value, C context);
5959

6060
/**
61-
* NoOp {@link PropertyValueConverter} implementation.
61+
* No-op {@link PropertyValueConverter} implementation.
6262
*
6363
* @author Christoph Strobl
6464
*/
@@ -67,13 +67,15 @@ enum ObjectToObjectPropertyValueConverter implements PropertyValueConverter {
6767

6868
INSTANCE;
6969

70+
@Nullable
7071
@Override
71-
public Object read(Object value, ValueConversionContext context) {
72+
public Object read(@Nullable Object value, ValueConversionContext context) {
7273
return value;
7374
}
7475

76+
@Nullable
7577
@Override
76-
public Object write(Object value, ValueConversionContext context) {
78+
public Object write(@Nullable Object value, ValueConversionContext context) {
7779
return value;
7880
}
7981
}
@@ -83,26 +85,28 @@ public Object write(Object value, ValueConversionContext context) {
8385
*
8486
* @author Oliver Drotbohm
8587
*/
86-
class FunctionPropertyValueConverter<A, B, P extends PersistentProperty<P>>
87-
implements PropertyValueConverter<A, B, ValueConversionContext<P>> {
88+
class FunctionPropertyValueConverter<DV, SV, P extends PersistentProperty<P>>
89+
implements PropertyValueConverter<DV, SV, ValueConversionContext<P>> {
8890

89-
private final BiFunction<A, ValueConversionContext<P>, B> writer;
90-
private final BiFunction<B, ValueConversionContext<P>, A> reader;
91+
private final BiFunction<DV, ValueConversionContext<P>, SV> writer;
92+
private final BiFunction<SV, ValueConversionContext<P>, DV> reader;
9193

92-
public FunctionPropertyValueConverter(BiFunction<A, ValueConversionContext<P>, B> writer,
93-
BiFunction<B, ValueConversionContext<P>, A> reader) {
94+
public FunctionPropertyValueConverter(BiFunction<DV, ValueConversionContext<P>, SV> writer,
95+
BiFunction<SV, ValueConversionContext<P>, DV> reader) {
9496

9597
this.writer = writer;
9698
this.reader = reader;
9799
}
98100

101+
@Nullable
99102
@Override
100-
public B write(A value, ValueConversionContext<P> context) {
103+
public SV write(@Nullable DV value, ValueConversionContext<P> context) {
101104
return writer.apply(value, context);
102105
}
103106

107+
@Nullable
104108
@Override
105-
public A read(B value, ValueConversionContext<P> context) {
109+
public DV read(@Nullable SV value, ValueConversionContext<P> context) {
106110
return reader.apply(value, context);
107111
}
108112
}

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

+24-23
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@
1818
import java.util.Arrays;
1919
import java.util.Collections;
2020
import java.util.EnumSet;
21-
import java.util.HashMap;
2221
import java.util.List;
2322
import java.util.Map;
2423
import java.util.Objects;
2524
import java.util.Optional;
25+
import java.util.concurrent.ConcurrentHashMap;
2626

2727
import org.springframework.beans.BeanUtils;
2828
import org.springframework.beans.factory.BeanFactory;
29-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3029
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
3130
import org.springframework.data.mapping.PersistentProperty;
3231
import org.springframework.lang.Nullable;
@@ -120,29 +119,26 @@ static class BeanFactoryAwarePropertyValueConverterFactory implements PropertyVa
120119
}
121120

122121
@Override
123-
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
124-
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
122+
public <DV, SV, C extends ValueConversionContext<?>> PropertyValueConverter<DV, SV, C> getConverter(
123+
Class<? extends PropertyValueConverter<DV, SV, C>> converterType) {
125124

126-
Assert.state(beanFactory != null, "BeanFactory must not be null. Did you forget to set it!");
127125
Assert.notNull(converterType, "ConverterType must not be null!");
128126

129-
try {
130-
return beanFactory.getBean(converterType);
131-
} catch (NoSuchBeanDefinitionException exception) {
127+
PropertyValueConverter<DV, SV, C> converter = beanFactory.getBeanProvider(converterType).getIfAvailable();
132128

133-
if (beanFactory instanceof AutowireCapableBeanFactory) {
134-
return (PropertyValueConverter<S, T, C>) ((AutowireCapableBeanFactory) beanFactory).createBean(converterType,
135-
AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
136-
}
129+
if (converter == null && beanFactory instanceof AutowireCapableBeanFactory) {
130+
return (PropertyValueConverter<DV, SV, C>) ((AutowireCapableBeanFactory) beanFactory).createBean(converterType,
131+
AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
137132
}
138-
return null;
133+
134+
return converter;
139135
}
140136
}
141137

142138
/**
143139
* {@link PropertyValueConverterFactory} implementation that serves {@link PropertyValueConverter} from a given
144140
* {@link ValueConverterRegistry registry}.
145-
*
141+
*
146142
* @author Christoph Strobl
147143
* @since 2.7
148144
*/
@@ -158,9 +154,9 @@ static class ConfiguredInstanceServingValueConverterFactory implements PropertyV
158154

159155
@Nullable
160156
@Override
161-
public <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getConverter(
157+
public <DV, SV, C extends ValueConversionContext<?>> PropertyValueConverter<DV, SV, C> getConverter(
162158
PersistentProperty<?> property) {
163-
return (PropertyValueConverter<A, B, C>) converterRegistry.getConverter(property.getOwner().getType(),
159+
return (PropertyValueConverter<DV, SV, C>) converterRegistry.getConverter(property.getOwner().getType(),
164160
property.getName());
165161
}
166162

@@ -174,7 +170,7 @@ public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T,
174170
/**
175171
* {@link PropertyValueConverterFactory} implementation that caches converters provided by an underlying
176172
* {@link PropertyValueConverterFactory factory}.
177-
*
173+
*
178174
* @author Christoph Strobl
179175
* @since 2.7
180176
*/
@@ -191,7 +187,7 @@ static class CachingPropertyValueConverterFactory implements PropertyValueConver
191187

192188
@Nullable
193189
@Override
194-
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
190+
public <DV, SV, C extends ValueConversionContext<?>> PropertyValueConverter<DV, SV, C> getConverter(
195191
PersistentProperty<?> property) {
196192

197193
Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> converter = cache.get(property);
@@ -201,8 +197,8 @@ public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T,
201197
}
202198

203199
@Override
204-
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
205-
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
200+
public <DV, SV, C extends ValueConversionContext<?>> PropertyValueConverter<DV, SV, C> getConverter(
201+
Class<? extends PropertyValueConverter<DV, SV, C>> converterType) {
206202

207203
Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> converter = cache.get(converterType);
208204

@@ -212,8 +208,8 @@ public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T,
212208

213209
static class Cache {
214210

215-
Map<PersistentProperty<?>, Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>>> perPropertyCache = new HashMap<>();
216-
Map<Class<?>, Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>>> typeCache = new HashMap<>();
211+
Map<PersistentProperty<?>, Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>>> perPropertyCache = new ConcurrentHashMap<>();
212+
Map<Class<?>, Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>>> typeCache = new ConcurrentHashMap<>();
217213

218214
Optional<PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> get(PersistentProperty<?> property) {
219215
return perPropertyCache.get(property);
@@ -226,7 +222,12 @@ static class Cache {
226222
<S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> cache(PersistentProperty<?> property,
227223
@Nullable PropertyValueConverter<S, T, C> converter) {
228224
perPropertyCache.putIfAbsent(property, Optional.ofNullable(converter));
229-
cache(property.getValueConverterType(), converter);
225+
226+
Class<? extends PropertyValueConverter<?, ?, ? extends ValueConversionContext<? extends PersistentProperty<?>>>> valueConverterType = property
227+
.getValueConverterType();
228+
if (valueConverterType != null) {
229+
cache(valueConverterType, converter);
230+
}
230231
return converter;
231232
}
232233

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -44,35 +44,35 @@ public interface PropertyValueConverterFactory {
4444
* Get the {@link PropertyValueConverter} applicable for the given {@link PersistentProperty}.
4545
*
4646
* @param property must not be {@literal null}.
47-
* @param <A> domain specific type.
48-
* @param <B> store native type.
47+
* @param <DV> domain-specific type.
48+
* @param <SV> store-native type.
4949
* @param <C> value conversion context to use.
5050
* @return can be {@literal null}.
5151
*/
52-
@Nullable
5352
@SuppressWarnings("unchecked")
54-
default <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getConverter(
53+
@Nullable
54+
default <DV, SV, C extends ValueConversionContext<?>> PropertyValueConverter<DV, SV, C> getConverter(
5555
PersistentProperty<?> property) {
5656

5757
if (!property.hasValueConverter()) {
5858
return null;
5959
}
6060

61-
return getConverter((Class<PropertyValueConverter<A, B, C>>) property.getValueConverterType());
61+
return getConverter((Class<PropertyValueConverter<DV, SV, C>>) property.getValueConverterType());
6262
}
6363

6464
/**
6565
* Get the converter by its type.
6666
*
6767
* @param converterType must not be {@literal null}.
68-
* @param <A> domain specific type.
69-
* @param <B> store native type.
68+
* @param <DV> domain-specific type.
69+
* @param <SV> store-native type.
7070
* @param <C> value conversion context to use.
71-
* @return
71+
* @return can be {@literal null}.
7272
*/
7373
@Nullable
74-
<A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getConverter(
75-
Class<? extends PropertyValueConverter<A, B, C>> converterType);
74+
<DV, SV, C extends ValueConversionContext<?>> PropertyValueConverter<DV, SV, C> getConverter(
75+
Class<? extends PropertyValueConverter<DV, SV, C>> converterType);
7676

7777
/**
7878
* Obtain a simple {@link PropertyValueConverterFactory} capable of instantiating {@link PropertyValueConverter}

0 commit comments

Comments
 (0)