type, String propertyName,
@SuppressWarnings("unused") Class propertyType) {
+
return new WritingConverterRegistrationBuilder<>(type, propertyName, this);
}
/**
- * Register the given converter for the types property identified via its name.
+ * Register the given {@link PropertyValueConverter converter} for the given type and property identified by
+ * its name.
*
* @param type the domain type to obtain the property from
* @param path the property name.
- * @param converter the converter to apply.
+ * @param converter the {@link PropertyValueConverter converter} to apply.
* @return this.
*/
public PropertyValueConverterRegistrar registerConverter(Class> type, String path,
@@ -88,33 +93,39 @@ public class PropertyValueConverterRegistrar
> {
registry.registerConverter(type, path,
(PropertyValueConverter, ?, ? extends ValueConversionContext
>) converter);
+
return this;
}
+ /**
+ * Register collected {@link PropertyValueConverter converters} within the given
+ * {@link ValueConverterRegistry registry}.
+ *
+ * @param target {@link ValueConverterRegistry} from which to register {@link PropertyValueConverter converters};
+ * must not be {@literal null}.
+ * @throws IllegalArgumentException if the {@link ValueConverterRegistry} is {@literal null}.
+ * @see ValueConverterRegistry
+ */
+ public void registerConvertersIn(@NonNull ValueConverterRegistry
target) {
+
+ Assert.notNull(target, "Target registry must not be null!");
+
+ registry.getConverterRegistrationMap().forEach((key, value) ->
+ target.registerConverter(key.type, key.path, value));
+ }
+
/**
* Obtain the {@link SimplePropertyValueConverterRegistry}.
*
* @return new instance of {@link SimplePropertyValueConverterRegistry}.
*/
+ @NonNull
public ValueConverterRegistry
buildRegistry() {
return new SimplePropertyValueConverterRegistry<>(registry);
}
/**
- * Register collected {@link PropertyValueConverter converters} within the given {@link ValueConverterRegistry
- * registry}.
- */
- public void registerConvertersIn(ValueConverterRegistry
target) {
-
- Assert.notNull(target, "Target registry must not be null!");
-
- registry.getConverterRegistrationMap().entrySet().forEach(entry -> {
- target.registerConverter(entry.getKey().type, entry.getKey().path, entry.getValue());
- });
- }
-
- /**
- * Helper to build up a fluent registration API starting on
+ * Helper class used to build up a fluent registration API starting with writing.
*
* @author Oliver Drotbohm
*/
@@ -123,10 +134,11 @@ public class PropertyValueConverterRegistrar
> {
private final Consumer>> registration;
private final PropertyValueConverterRegistrar config;
- WritingConverterRegistrationBuilder(Class type, String property, PropertyValueConverterRegistrar config) {
+ WritingConverterRegistrationBuilder(Class type, String property,
+ @NonNull PropertyValueConverterRegistrar config) {
this.config = config;
- this.registration = (converter) -> config.registerConverter(type, property, converter);
+ this.registration = converter -> config.registerConverter(type, property, converter);
}
public ReadingConverterRegistrationBuilder writingAsIs() {
@@ -146,12 +158,13 @@ public class PropertyValueConverterRegistrar> {
*/
public ReadingConverterRegistrationBuilder writing(
BiFunction, R> writer) {
+
return new ReadingConverterRegistrationBuilder<>(this, writer);
}
}
/**
- * A helper to build a fluent API to register how to read a database value into a domain object property.
+ * Helper class used to build a fluent API to register how to read a database value into a domain object property.
*
* @author Oliver Drotbohm
*/
@@ -160,12 +173,14 @@ public class PropertyValueConverterRegistrar> {
private final WritingConverterRegistrationBuilder origin;
private final BiFunction, R> writer;
- ReadingConverterRegistrationBuilder(WritingConverterRegistrationBuilder origin,
- BiFunction, R> writer) {
+ ReadingConverterRegistrationBuilder(@NonNull WritingConverterRegistrationBuilder origin,
+ @NonNull BiFunction, R> writer) {
+
this.origin = origin;
this.writer = writer;
}
+ @SuppressWarnings("unchecked")
public PropertyValueConverterRegistrar readingAsIs() {
return reading((source, context) -> (S) source);
}
@@ -178,8 +193,9 @@ public class PropertyValueConverterRegistrar
> {
* Describes how to read a database value into a domain object's property value.
*
* @param reader must not be {@literal null}.
- * @return
+ * @return the confiured {@link PropertyValueConverterRegistrar}.
*/
+ @SuppressWarnings({ "rawtypes", "unchecked" })
public PropertyValueConverterRegistrar
reading(BiFunction, S> reader) {
origin.registration.accept(new FunctionPropertyValueConverter(writer, reader));
diff --git a/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java b/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java
index bb58214be..70f61ac6f 100644
--- a/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java
+++ b/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java
@@ -17,73 +17,93 @@ package org.springframework.data.convert;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.convert.PropertyValueConverterFactories.ChainedPropertyValueConverterFactory;
import org.springframework.data.mapping.PersistentProperty;
+import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
/**
- * {@link PropertyValueConversions} implementation that allows to pick a {@link PropertyValueConverterFactory} serving
- * {@link PropertyValueConverter converters}. Activating {@link #setConverterCacheEnabled(boolean) cahing} allows to
- * reuse converters. Providing a {@link SimplePropertyValueConverterRegistry} adds path configured converter instances.
+ * {@link PropertyValueConversions} implementation allowing a {@link PropertyValueConverterFactory} creating
+ * {@link PropertyValueConverter converters} to be chosen. Activating {@link #setConverterCacheEnabled(boolean) cahing}
+ * allows converters to be reused.
*
- * Should be {@link #afterPropertiesSet() initialized}. If not, {@link #init()} will be called of fist attempt of
- * {@link PropertyValueConverter converter} retrieval.
+ * Providing a {@link SimplePropertyValueConverterRegistry} adds path configured converter instances.
+ *
+ * This class should be {@link #afterPropertiesSet() initialized}. If not, {@link #init()} will be called on the first
+ * attempt of {@link PropertyValueConverter converter} retrieval.
*
* @author Christoph Strobl
* @author Mark Paluch
+ * @see PropertyValueConversions
+ * @see InitializingBean
* @since 2.7
*/
public class SimplePropertyValueConversions implements PropertyValueConversions, InitializingBean {
- private @Nullable PropertyValueConverterFactory converterFactory;
- private @Nullable ValueConverterRegistry> valueConverterRegistry;
+ private static final String NO_CONVERTER_FACTORY_ERROR_MESSAGE =
+ "PropertyValueConverterFactory is not set. Make sure to either set the converter factory or call afterPropertiesSet() to initialize the object.";
+
private boolean converterCacheEnabled = true;
+ private @Nullable PropertyValueConverterFactory converterFactory;
+
+ private @Nullable ValueConverterRegistry> valueConverterRegistry;
+
/**
- * Set the {@link PropertyValueConverterFactory factory} responsible for creating the actual
- * {@link PropertyValueConverter converter}.
+ * Set the {@link PropertyValueConverterFactory} responsible for creating the actual {@link PropertyValueConverter}.
*
- * @param converterFactory must not be {@literal null}.
+ * @param converterFactory {@link PropertyValueConverterFactory} used to create the actual
+ * {@link PropertyValueConverter}.
+ * @see PropertyValueConverterFactory
*/
- public void setConverterFactory(PropertyValueConverterFactory converterFactory) {
+ public void setConverterFactory(@Nullable PropertyValueConverterFactory converterFactory) {
this.converterFactory = converterFactory;
}
+ /**
+ * Returns the configured {@link PropertyValueConverterFactory} responsible for creating the actual
+ * {@link PropertyValueConverter}.
+ *
+ * @return the configured {@link PropertyValueConverterFactory}; can be {@literal null}.
+ * @see PropertyValueConverterFactory
+ */
@Nullable
public PropertyValueConverterFactory getConverterFactory() {
return converterFactory;
}
- private PropertyValueConverterFactory obtainConverterFactory() {
+ private @NonNull PropertyValueConverterFactory requireConverterFactory() {
PropertyValueConverterFactory factory = getConverterFactory();
- if (factory == null) {
- throw new IllegalStateException(
- "PropertyValueConverterFactory is not set. Make sure to either set the converter factory or call afterPropertiesSet() to initialize the object.");
- }
+ Assert.state(factory != null, NO_CONVERTER_FACTORY_ERROR_MESSAGE);
return factory;
}
/**
- * Set the {@link ValueConverterRegistry converter registry} for path configured converters. This is short for adding
- * a
+ * Set the {@link ValueConverterRegistry converter registry} used for path configured converters.
+ *
+ * This is short for adding a
* {@link org.springframework.data.convert.PropertyValueConverterFactories.ConfiguredInstanceServingValueConverterFactory}
* at the end of a {@link ChainedPropertyValueConverterFactory}.
*
- * @param valueConverterRegistry must not be {@literal null}.
+ * @param valueConverterRegistry registry of {@link PropertyValueConverter PropertyValueConverters}.
+ * @see ValueConverterRegistry
*/
- public void setValueConverterRegistry(ValueConverterRegistry> valueConverterRegistry) {
+ public void setValueConverterRegistry(@Nullable ValueConverterRegistry> valueConverterRegistry) {
this.valueConverterRegistry = valueConverterRegistry;
}
/**
* Get the {@link ValueConverterRegistry} used for path configured converters.
*
- * @return can be {@literal null}.
+ * @return the configured {@link ValueConverterRegistry}; can be {@literal null}.
+ * @see ValueConverterRegistry
*/
@Nullable
public ValueConverterRegistry> getValueConverterRegistry() {
@@ -91,29 +111,37 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
}
/**
- * Configure whether to use converter cache. Enabled by default.
+ * Configure whether to use converter the cache. Enabled by default.
*
- * @param converterCacheEnabled set to {@literal true} to enable caching of {@link PropertyValueConverter converter}
- * instances.
+ * @param converterCacheEnabled set to {@literal true} to enable caching of
+ * {@link PropertyValueConverter converter} instances.
*/
public void setConverterCacheEnabled(boolean converterCacheEnabled) {
this.converterCacheEnabled = converterCacheEnabled;
}
+ /**
+ * Determines whether a {@link PropertyValueConverter} has been registered for
+ * the given {@link PersistentProperty property}.
+ *
+ * @param property {@link PersistentProperty} to evaluate.
+ * @return {@literal true} if a {@link PropertyValueConverter} has been registered for
+ * the given {@link PersistentProperty property}.
+ * @see PersistentProperty
+ */
@Override
public boolean hasValueConverter(PersistentProperty> property) {
- return obtainConverterFactory().getConverter(property) != null;
+ return requireConverterFactory().getConverter(property) != null;
}
+ @NonNull
@Override
public , D extends ValueConversionContext> PropertyValueConverter getValueConverter(
P property) {
- PropertyValueConverter converter = obtainConverterFactory().getConverter(property);
+ PropertyValueConverter converter = requireConverterFactory().getConverter(property);
- if (converter == null) {
- throw new IllegalArgumentException(String.format("No PropertyValueConverter registered for %s", property));
- }
+ Assert.notNull(converter, String.format("No PropertyValueConverter registered for %s", property));
return converter;
}
@@ -125,15 +153,10 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
List factoryList = new ArrayList<>(3);
- if (converterFactory != null) {
- factoryList.add(converterFactory);
- } else {
- factoryList.add(PropertyValueConverterFactory.simple());
- }
+ factoryList.add(resolveConverterFactory());
- if ((valueConverterRegistry != null) && !valueConverterRegistry.isEmpty()) {
- factoryList.add(PropertyValueConverterFactory.configuredInstance(valueConverterRegistry));
- }
+ resolveConverterRegistryAsConverterFactory()
+ .ifPresent(factoryList::add);
PropertyValueConverterFactory targetFactory = factoryList.size() > 1
? PropertyValueConverterFactory.chained(factoryList)
@@ -143,6 +166,26 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
: targetFactory;
}
+ private @NonNull PropertyValueConverterFactory resolveConverterFactory() {
+
+ PropertyValueConverterFactory converterFactory = getConverterFactory();
+
+ return converterFactory != null ? converterFactory
+ : PropertyValueConverterFactory.simple();
+ }
+
+ private Optional resolveConverterRegistryAsConverterFactory() {
+
+ return Optional.ofNullable(getValueConverterRegistry())
+ .filter(it -> !it.isEmpty())
+ .map(PropertyValueConverterFactory::configuredInstance);
+ }
+
+ /**
+ * Initializes this {@link SimplePropertyValueConversions} instance.
+ *
+ * @see #init()
+ */
@Override
public void afterPropertiesSet() {
init();
diff --git a/src/main/java/org/springframework/data/convert/ValueConversionContext.java b/src/main/java/org/springframework/data/convert/ValueConversionContext.java
index 049485af0..ece29d117 100644
--- a/src/main/java/org/springframework/data/convert/ValueConversionContext.java
+++ b/src/main/java/org/springframework/data/convert/ValueConversionContext.java
@@ -18,6 +18,7 @@ package org.springframework.data.convert;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
+import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
/**
@@ -29,6 +30,7 @@ import org.springframework.lang.Nullable;
*
* @author Christoph Strobl
* @author Oliver Drotbohm
+ * @see org.springframework.data.mapping.PersistentProperty
*/
public interface ValueConversionContext> {
@@ -36,14 +38,19 @@ public interface ValueConversionContext
> {
* Return the {@link PersistentProperty} to be handled.
*
* @return will never be {@literal null}.
+ * @see org.springframework.data.mapping.PersistentProperty
*/
P getProperty();
/**
- * Write to whatever type is considered best for the given source.
+ * Write the value as an instance of the {@link PersistentProperty#getTypeInformation() property type}.
*
- * @param value
- * @return
+ * @param value {@link Object value} to write; can be {@literal null}.
+ * @return can be {@literal null}.
+ * @throws IllegalStateException if value cannot be written as an instance of the
+ * {@link PersistentProperty#getTypeInformation() property type}.
+ * @see PersistentProperty#getTypeInformation()
+ * @see #write(Object, TypeInformation)
*/
@Nullable
default Object write(@Nullable Object value) {
@@ -51,26 +58,31 @@ public interface ValueConversionContext
> {
}
/**
- * Write as the given type.
+ * Write the value as an instance of {@link Class type}.
*
- * @param value can be {@literal null}.
- * @param target must not be {@literal null}.
+ * @param value {@link Object value} to write; can be {@literal null}.
+ * @param target {@link Class type} of value to be written; must not be {@literal null}.
* @return can be {@literal null}.
+ * @throws IllegalStateException if value cannot be written as an instance of {@link Class type}.
+ * @see #write(Object, TypeInformation)
+ * @see ClassTypeInformation
*/
@Nullable
- default T write(@Nullable Object value, Class target) {
+ default T write(@Nullable Object value, @NonNull Class target) {
return write(value, ClassTypeInformation.from(target));
}
/**
- * Write as the given type.
+ * Write the value as an instance of {@link TypeInformation type}.
*
- * @param value can be {@literal null}.
- * @param target must not be {@literal null}.
+ * @param value {@link Object value} to write; can be {@literal null}.
+ * @param target {@link TypeInformation type} of value to be written; must not be {@literal null}.
* @return can be {@literal null}.
+ * @throws IllegalStateException if value cannot be written as an instance of {@link TypeInformation type}.
+ * @see TypeInformation
*/
@Nullable
- default T write(@Nullable Object value, TypeInformation target) {
+ default T write(@Nullable Object value, @NonNull TypeInformation target) {
if (value == null || target.getType().isInstance(value)) {
return target.getType().cast(value);
@@ -81,10 +93,14 @@ public interface ValueConversionContext> {
}
/**
- * Reads the value into the type of the current property.
+ * Reads the value as an instance of the {@link PersistentProperty#getTypeInformation() property type}.
*
- * @param value can be {@literal null}.
+ * @param value {@link Object value} to be read; can be {@literal null}.
* @return can be {@literal null}.
+ * @throws IllegalStateException if value cannot be read as an instance of the
+ * {@link PersistentProperty#getTypeInformation() property type}.
+ * @see PersistentProperty#getTypeInformation()
+ * @see #read(Object, TypeInformation)
*/
@Nullable
default Object read(@Nullable Object value) {
@@ -92,32 +108,37 @@ public interface ValueConversionContext
> {
}
/**
- * Reads the value as the given type.
+ * Reads the value as an instance of {@link Class type}.
*
- * @param value can be {@literal null}.
- * @param target must not be {@literal null}.
+ * @param value {@link Object value} to be read; can be {@literal null}.
+ * @param target {@link Class type} of value to be read; must not be {@literal null}.
* @return can be {@literal null}.
+ * @throws IllegalStateException if value cannot be read as an instance of {@link Class type}.
+ * @see #read(Object, TypeInformation)
+ * @see ClassTypeInformation
*/
@Nullable
- default T read(@Nullable Object value, Class target) {
+ default T read(@Nullable Object value, @NonNull Class target) {
return read(value, ClassTypeInformation.from(target));
}
/**
- * Reads the value as the given type.
+ * Reads the value as an instance of {@link TypeInformation type}.
*
- * @param value can be {@literal null}.
- * @param target must not be {@literal null}.
+ * @param value {@link Object value} to be read; can be {@literal null}.
+ * @param target {@link TypeInformation type} of value to be read; must not be {@literal null}.
* @return can be {@literal null}.
+ * @throws IllegalStateException if value cannot be read as an instance of {@link TypeInformation type}.
+ * @see TypeInformation
*/
@Nullable
- default T read(@Nullable Object value, TypeInformation target) {
+ default T read(@Nullable Object value, @NonNull TypeInformation target) {
if (value == null || target.getType().isInstance(value)) {
return target.getType().cast(value);
}
throw new IllegalStateException(String.format(
- "%s does not provide write function that allows value conversion to target type (%s).", getClass(), target));
+ "%s does not provide read function that allows value conversion to target type (%s).", getClass(), target));
}
}
diff --git a/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java b/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java
index 8b516b63a..960fe8fbb 100644
--- a/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java
+++ b/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java
@@ -19,16 +19,17 @@ import org.springframework.data.mapping.PersistentProperty;
import org.springframework.lang.Nullable;
/**
- * A registry of property-specific {@link PropertyValueConverter value converters} to convert only specific
- * properties/values of an object.
+ * A registry of {@link PersistentProperty property-specific} {@link PropertyValueConverter value converters}
+ * to convert only specific properties/values of an object.
*
* @author Christoph Strobl
+ * @see PropertyValueConverter
* @since 2.7
*/
public interface ValueConverterRegistry> {
/**
- * Register the {@link PropertyValueConverter} for the property of the given type.
+ * Register the {@link PropertyValueConverter} for the {@link PersistentProperty property} of the given type.
*
* @param type the target type. Must not be {@literal null}.
* @param path the property name. Must not be {@literal null}.
@@ -38,12 +39,13 @@ public interface ValueConverterRegistry
> {
PropertyValueConverter, ?, ? extends ValueConversionContext
> converter);
/**
- * Obtain the converter registered for the given type, path combination or {@literal null} if none defined.
+ * Obtain the {@link PropertyValueConverter} registered for the given type, path combination or {@literal null}
+ * if none defined.
*
* @param type the target type. Must not be {@literal null}.
* @param path the property name. Must not be {@literal null}.
- * @param
- * @param
+ * @param domain-specific type.
+ * @param store-specific type.
* @return {@literal null} if no converter present for the given type/path combination.
*/
@Nullable
@@ -54,7 +56,7 @@ public interface ValueConverterRegistry> {
*
* @param type the target type. Must not be {@literal null}.
* @param path the property name. Must not be {@literal null}.
- * @return {@literal false} if no converter present for the given type/path combination.
+ * @return {@literal false} if no converter is present for the given type/path combination.
*/
default boolean containsConverterFor(Class> type, String path) {
return getConverter(type, path) != null;
@@ -68,10 +70,10 @@ public interface ValueConverterRegistry
> {
/**
* Obtain a simple {@link ValueConverterRegistry}.
*
- * @param
+ * @param {@link PersistentProperty} type.
* @return new instance of {@link ValueConverterRegistry}.
*/
- static > ValueConverterRegistry simple() {
+ static > ValueConverterRegistry
simple() {
return new SimplePropertyValueConverterRegistry<>();
}
}