Fluent registration API for PropertyValueConverters.
Introduce a builder API to register PropertyValueConverters using simple (Bi)Functions. Additional methods on ValueConversionContext to enable advanced use cases in converter implementation. Tweak generics of VCC to be able to expose store-specific PersistentProperty implementations via the context. See #1484 Original pull request: #2566.
This commit is contained in:
committed by
Mark Paluch
parent
caf49ad739
commit
e7292279bf
@@ -33,6 +33,7 @@ import org.springframework.core.convert.converter.GenericConverter;
|
|||||||
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
|
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
|
||||||
import org.springframework.core.convert.support.GenericConversionService;
|
import org.springframework.core.convert.support.GenericConversionService;
|
||||||
import org.springframework.data.convert.ConverterBuilder.ConverterAware;
|
import org.springframework.data.convert.ConverterBuilder.ConverterAware;
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||||
import org.springframework.data.util.Predicates;
|
import org.springframework.data.util.Predicates;
|
||||||
@@ -199,7 +200,7 @@ public class CustomConversions {
|
|||||||
* @since ?
|
* @since ?
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public <A, B, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<A, B, C> getPropertyValueConverter(
|
public <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getPropertyValueConverter(
|
||||||
PersistentProperty<?> property) {
|
PersistentProperty<?> property) {
|
||||||
return propertyValueConversions != null ? propertyValueConversions.getValueConverter(property) : null;
|
return propertyValueConversions != null ? propertyValueConversions.getValueConverter(property) : null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,6 @@ public @interface PropertyConverter {
|
|||||||
*
|
*
|
||||||
* @return the configured {@link PropertyValueConverter}. {@link ObjectToObjectPropertyValueConverter} by default.
|
* @return the configured {@link PropertyValueConverter}. {@link ObjectToObjectPropertyValueConverter} by default.
|
||||||
*/
|
*/
|
||||||
Class<? extends PropertyValueConverter<?, ?, ? extends PropertyValueConverter.ValueConversionContext>> value() default ObjectToObjectPropertyValueConverter.class;
|
Class<? extends PropertyValueConverter> value() default ObjectToObjectPropertyValueConverter.class;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.convert;
|
package org.springframework.data.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ import org.springframework.lang.Nullable;
|
|||||||
* applied to a specific property. Other than {@link org.springframework.core.convert.converter.Converter converters}
|
* applied to a specific property. Other than {@link org.springframework.core.convert.converter.Converter converters}
|
||||||
* registered in {@link CustomConversions} the property based variants accept and allow returning {@literal null} values
|
* registered in {@link CustomConversions} the property based variants accept and allow returning {@literal null} values
|
||||||
* and provide access to a store specific {@link PropertyValueConverter.ValueConversionContext conversion context}.
|
* and provide access to a store specific {@link PropertyValueConverter.ValueConversionContext conversion context}.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @since ?
|
* @since ?
|
||||||
* @currentBook The Desert Prince - Peter V. Brett
|
* @currentBook The Desert Prince - Peter V. Brett
|
||||||
@@ -49,6 +50,6 @@ public interface PropertyValueConversions {
|
|||||||
* @return the suitable {@link PropertyValueConverter} or {@literal null} if none available.
|
* @return the suitable {@link PropertyValueConverter} or {@literal null} if none available.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
<A, B, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<A, B, C> getValueConverter(
|
<A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getValueConverter(
|
||||||
PersistentProperty<?> property);
|
PersistentProperty<?> property);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.convert;
|
package org.springframework.data.convert;
|
||||||
|
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +33,7 @@ import org.springframework.lang.Nullable;
|
|||||||
* @param <B> store native type
|
* @param <B> store native type
|
||||||
* @since 2.7
|
* @since 2.7
|
||||||
*/
|
*/
|
||||||
public interface PropertyValueConverter<A, B, C extends PropertyValueConverter.ValueConversionContext> {
|
public interface PropertyValueConverter<A, B, C extends ValueConversionContext<? extends PersistentProperty<?>>> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the given store specific value into it's domain value representation. Typically a {@literal read}
|
* Convert the given store specific value into it's domain value representation. Typically a {@literal read}
|
||||||
@@ -56,10 +59,86 @@ public interface PropertyValueConverter<A, B, C extends PropertyValueConverter.V
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
|
* @author Oliver Drotbohm
|
||||||
*/
|
*/
|
||||||
interface ValueConversionContext {
|
interface ValueConversionContext<P extends PersistentProperty<P>> {
|
||||||
|
|
||||||
PersistentProperty<?> getProperty();
|
/**
|
||||||
|
* Return the {@link PersistentProperty} to be handled.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
P getProperty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to whatever type is considered best for the given source.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default Object write(@Nullable Object value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write as the given type.
|
||||||
|
*
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @param target must not be {@literal null}.
|
||||||
|
* @return can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default <T> T write(@Nullable Object value, Class<T> target) {
|
||||||
|
return write(value, ClassTypeInformation.from(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write as the given type.
|
||||||
|
*
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @param target must not be {@literal null}.
|
||||||
|
* @return can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default <T> T write(@Nullable Object value, TypeInformation<T> target) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value into the type of the current property.
|
||||||
|
*
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @return can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default Object read(@Nullable Object value) {
|
||||||
|
return read(value, getProperty().getTypeInformation());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value as the given type.
|
||||||
|
*
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @param target must not be {@literal null}.
|
||||||
|
* @return can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default <T> T read(@Nullable Object value, Class<T> target) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value as the given type.
|
||||||
|
*
|
||||||
|
* @param value can be {@literal null}.
|
||||||
|
* @param target must not be {@literal null}.
|
||||||
|
* @return can be {@literal null}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default <T> T read(@Nullable Object value, TypeInformation<T> target) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +146,8 @@ public interface PropertyValueConverter<A, B, C extends PropertyValueConverter.V
|
|||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
enum ObjectToObjectPropertyValueConverter implements PropertyValueConverter<Object, Object, ValueConversionContext> {
|
@SuppressWarnings({ "rawtypes", "null" })
|
||||||
|
enum ObjectToObjectPropertyValueConverter implements PropertyValueConverter {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -81,5 +161,4 @@ public interface PropertyValueConverter<A, B, C extends PropertyValueConverter.V
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils;
|
|||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@@ -59,14 +60,14 @@ final class PropertyValueConverterFactories {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <A, B, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<A, B, C> getConverter(
|
public <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getConverter(
|
||||||
PersistentProperty<?> property) {
|
PersistentProperty<?> property) {
|
||||||
return delegates.stream().map(it -> (PropertyValueConverter<A, B, C>) it.getConverter(property))
|
return delegates.stream().map(it -> (PropertyValueConverter<A, B, C>) it.getConverter(property))
|
||||||
.filter(Objects::nonNull).findFirst().orElse(null);
|
.filter(Objects::nonNull).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
return delegates.stream().filter(it -> it.getConverter(converterType) != null).findFirst()
|
return delegates.stream().filter(it -> it.getConverter(converterType) != null).findFirst()
|
||||||
.map(it -> it.getConverter(converterType)).orElse(null);
|
.map(it -> it.getConverter(converterType)).orElse(null);
|
||||||
@@ -82,7 +83,7 @@ final class PropertyValueConverterFactories {
|
|||||||
static class SimplePropertyConverterFactory implements PropertyValueConverterFactory {
|
static class SimplePropertyConverterFactory implements PropertyValueConverterFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
|
|
||||||
Assert.notNull(converterType, "ConverterType must not be null!");
|
Assert.notNull(converterType, "ConverterType must not be null!");
|
||||||
@@ -110,7 +111,7 @@ final class PropertyValueConverterFactories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
|
|
||||||
Assert.state(beanFactory != null, "BeanFactory must not be null. Did you forget to set it!");
|
Assert.state(beanFactory != null, "BeanFactory must not be null. Did you forget to set it!");
|
||||||
@@ -145,14 +146,14 @@ final class PropertyValueConverterFactories {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <A, B, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<A, B, C> getConverter(
|
public <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getConverter(
|
||||||
PersistentProperty<?> property) {
|
PersistentProperty<?> property) {
|
||||||
return (PropertyValueConverter<A, B, C>) conversionsRegistrar.getConverter(property.getOwner().getType(),
|
return (PropertyValueConverter<A, B, C>) conversionsRegistrar.getConverter(property.getOwner().getType(),
|
||||||
property.getName());
|
property.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -170,55 +171,55 @@ final class PropertyValueConverterFactories {
|
|||||||
private final Cache cache = new Cache();
|
private final Cache cache = new Cache();
|
||||||
|
|
||||||
public CachingPropertyValueConverterFactory(PropertyValueConverterFactory delegate) {
|
public CachingPropertyValueConverterFactory(PropertyValueConverterFactory delegate) {
|
||||||
|
|
||||||
Assert.notNull(delegate, "Delegate must not be null!");
|
Assert.notNull(delegate, "Delegate must not be null!");
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
PersistentProperty<?> property) {
|
PersistentProperty<?> property) {
|
||||||
|
|
||||||
PropertyValueConverter converter = cache.get(property);
|
PropertyValueConverter converter = cache.get(property);
|
||||||
if (converter != null) {
|
|
||||||
return converter;
|
return converter != null
|
||||||
}
|
? converter
|
||||||
return cache.cache(property, delegate.getConverter(property));
|
: cache.cache(property, delegate.getConverter(property));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
|
|
||||||
PropertyValueConverter converter = cache.get(converterType);
|
PropertyValueConverter converter = cache.get(converterType);
|
||||||
if (converter != null) {
|
|
||||||
return converter;
|
return converter != null
|
||||||
}
|
? converter
|
||||||
return cache.cache(converterType, delegate.getConverter(converterType));
|
: cache.cache(converterType, delegate.getConverter(converterType));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Cache {
|
static class Cache {
|
||||||
|
|
||||||
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ? extends PropertyValueConverter.ValueConversionContext>> perPropertyCache = new HashMap<>();
|
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> perPropertyCache = new HashMap<>();
|
||||||
Map<Class<?>, PropertyValueConverter<?, ?, ? extends PropertyValueConverter.ValueConversionContext>> typeCache = new HashMap<>();
|
Map<Class<?>, PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> typeCache = new HashMap<>();
|
||||||
|
|
||||||
PropertyValueConverter<?, ?, ? extends PropertyValueConverter.ValueConversionContext> get(PersistentProperty<?> property) {
|
PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>> get(PersistentProperty<?> property) {
|
||||||
return perPropertyCache.get(property);
|
return perPropertyCache.get(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyValueConverter<?, ?, ? extends PropertyValueConverter.ValueConversionContext> get(Class<?> type) {
|
PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>> get(Class<?> type) {
|
||||||
return typeCache.get(type);
|
return typeCache.get(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
<S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> cache(PersistentProperty<?> property,
|
<S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> cache(PersistentProperty<?> property,
|
||||||
PropertyValueConverter<S, T, C> converter) {
|
PropertyValueConverter<S, T, C> converter) {
|
||||||
perPropertyCache.putIfAbsent(property, converter);
|
perPropertyCache.putIfAbsent(property, converter);
|
||||||
cache(property.getValueConverterType(), converter);
|
cache(property.getValueConverterType(), converter);
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
<S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> cache(Class<?> type,
|
<S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> cache(Class<?> type,
|
||||||
PropertyValueConverter<S, T, C> converter) {
|
PropertyValueConverter<S, T, C> converter) {
|
||||||
typeCache.putIfAbsent(type, converter);
|
typeCache.putIfAbsent(type, converter);
|
||||||
return converter;
|
return converter;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.convert.PropertyValueConverterFactories.BeanFactoryAwarePropertyValueConverterFactory;
|
import org.springframework.data.convert.PropertyValueConverterFactories.BeanFactoryAwarePropertyValueConverterFactory;
|
||||||
import org.springframework.data.convert.PropertyValueConverterFactories.CachingPropertyValueConverterFactory;
|
import org.springframework.data.convert.PropertyValueConverterFactories.CachingPropertyValueConverterFactory;
|
||||||
import org.springframework.data.convert.PropertyValueConverterFactories.CompositePropertyValueConverterFactory;
|
import org.springframework.data.convert.PropertyValueConverterFactories.CompositePropertyValueConverterFactory;
|
||||||
@@ -49,7 +50,8 @@ public interface PropertyValueConverterFactory {
|
|||||||
* @return can be {@literal null}.
|
* @return can be {@literal null}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
default <A, B, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<A, B, C> getConverter(
|
@SuppressWarnings("unchecked")
|
||||||
|
default <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getConverter(
|
||||||
PersistentProperty<?> property) {
|
PersistentProperty<?> property) {
|
||||||
|
|
||||||
if (!property.hasValueConverter()) {
|
if (!property.hasValueConverter()) {
|
||||||
@@ -59,7 +61,7 @@ public interface PropertyValueConverterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
<S, T, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
<S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType);
|
Class<? extends PropertyValueConverter<S, T, C>> converterType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A, B, C extends PropertyValueConverter.ValueConversionContext> PropertyValueConverter<A, B, C> getValueConverter(
|
public <A, B, C extends ValueConversionContext<?>> PropertyValueConverter<A, B, C> getValueConverter(
|
||||||
PersistentProperty<?> property) {
|
PersistentProperty<?> property) {
|
||||||
|
|
||||||
if (!initialized.get()) {
|
if (!initialized.get()) {
|
||||||
@@ -68,7 +69,7 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
|
|||||||
factoryList.add(PropertyValueConverterFactory.simple());
|
factoryList.add(PropertyValueConverterFactory.simple());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (converterRegistrar != null && !converterRegistrar.isEmpty()) {
|
if ((converterRegistrar != null) && !converterRegistrar.isEmpty()) {
|
||||||
factoryList.add(PropertyValueConverterFactory.configuredInstance(converterRegistrar));
|
factoryList.add(PropertyValueConverterFactory.configuredInstance(converterRegistrar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -427,9 +427,12 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
default Class<? extends PropertyValueConverter<?,?, ? extends ValueConversionContext>> getValueConverterType() {
|
default Class<? extends PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> getValueConverterType() {
|
||||||
|
|
||||||
PropertyConverter annotation = findAnnotation(PropertyConverter.class);
|
PropertyConverter annotation = findAnnotation(PropertyConverter.class);
|
||||||
return annotation == null ? null : annotation.value();
|
|
||||||
|
return annotation == null ? null
|
||||||
|
: (Class<? extends PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>>) annotation.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean hasValueConverter() {
|
default boolean hasValueConverter() {
|
||||||
|
|||||||
@@ -287,10 +287,12 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends PropertyValueConverter<?, ?, ? extends ValueConversionContext>> getValueConverterType() {
|
@SuppressWarnings("unchecked")
|
||||||
|
public Class<? extends PropertyValueConverter<?, ?, ? extends ValueConversionContext<?>>> getValueConverterType() {
|
||||||
|
|
||||||
return doFindAnnotation(PropertyConverter.class) //
|
return doFindAnnotation(PropertyConverter.class) //
|
||||||
.map(PropertyConverter::value) //
|
.map(PropertyConverter::value) //
|
||||||
|
.map(Class.class::cast) //
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
|||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
|
import org.springframework.data.mapping.context.SamplePersistentProperty;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,14 +115,14 @@ public class PropertyValueConverterFactoryUnitTests {
|
|||||||
PropertyValueConverterFactory factory = PropertyValueConverterFactory.chained(new PropertyValueConverterFactory() {
|
PropertyValueConverterFactory factory = PropertyValueConverterFactory.chained(new PropertyValueConverterFactory() {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}, new PropertyValueConverterFactory() {
|
}, new PropertyValueConverterFactory() {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
return expected;
|
return expected;
|
||||||
}
|
}
|
||||||
@@ -136,14 +137,14 @@ public class PropertyValueConverterFactoryUnitTests {
|
|||||||
PropertyValueConverterFactory factory = PropertyValueConverterFactory.chained(new PropertyValueConverterFactory() {
|
PropertyValueConverterFactory factory = PropertyValueConverterFactory.chained(new PropertyValueConverterFactory() {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}, new PropertyValueConverterFactory() {
|
}, new PropertyValueConverterFactory() {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <S, T, C extends ValueConversionContext> PropertyValueConverter<S, T, C> getConverter(
|
public <S, T, C extends ValueConversionContext<?>> PropertyValueConverter<S, T, C> getConverter(
|
||||||
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
Class<? extends PropertyValueConverter<S, T, C>> converterType) {
|
||||||
throw new RuntimeException("can't touch this!");
|
throw new RuntimeException("can't touch this!");
|
||||||
}
|
}
|
||||||
@@ -176,22 +177,23 @@ public class PropertyValueConverterFactoryUnitTests {
|
|||||||
.isSameAs(factory.getConverter(ConverterWithDefaultCtor.class)); // TODO: is this a valid assumption?
|
.isSameAs(factory.getConverter(ConverterWithDefaultCtor.class)); // TODO: is this a valid assumption?
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ConverterWithDefaultCtor implements PropertyValueConverter<String, UUID, ValueConversionContext> {
|
static class ConverterWithDefaultCtor
|
||||||
|
implements PropertyValueConverter<String, UUID, ValueConversionContext<SamplePersistentProperty>> {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String nativeToDomain(@Nullable UUID nativeValue, ValueConversionContext context) {
|
public String nativeToDomain(@Nullable UUID nativeValue, ValueConversionContext<SamplePersistentProperty> context) {
|
||||||
return nativeValue.toString();
|
return nativeValue.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public UUID domainToNative(@Nullable String domainValue, ValueConversionContext context) {
|
public UUID domainToNative(@Nullable String domainValue, ValueConversionContext<SamplePersistentProperty> context) {
|
||||||
return UUID.fromString(domainValue);
|
return UUID.fromString(domainValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ConverterEnum implements PropertyValueConverter<String, UUID, ValueConversionContext> {
|
enum ConverterEnum implements PropertyValueConverter<String, UUID, ValueConversionContext<SamplePersistentProperty>> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
|
||||||
@@ -208,7 +210,8 @@ public class PropertyValueConverterFactoryUnitTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ConverterWithDependency implements PropertyValueConverter<String, UUID, ValueConversionContext> {
|
static class ConverterWithDependency
|
||||||
|
implements PropertyValueConverter<String, UUID, ValueConversionContext<SamplePersistentProperty>> {
|
||||||
|
|
||||||
private final SomeDependency someDependency;
|
private final SomeDependency someDependency;
|
||||||
|
|
||||||
@@ -218,7 +221,7 @@ public class PropertyValueConverterFactoryUnitTests {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String nativeToDomain(@Nullable UUID nativeValue, ValueConversionContext context) {
|
public String nativeToDomain(@Nullable UUID nativeValue, ValueConversionContext<SamplePersistentProperty> context) {
|
||||||
|
|
||||||
assertThat(someDependency).isNotNull();
|
assertThat(someDependency).isNotNull();
|
||||||
return nativeValue.toString();
|
return nativeValue.toString();
|
||||||
@@ -226,7 +229,7 @@ public class PropertyValueConverterFactoryUnitTests {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public UUID domainToNative(@Nullable String domainValue, ValueConversionContext context) {
|
public UUID domainToNative(@Nullable String domainValue, ValueConversionContext<SamplePersistentProperty> context) {
|
||||||
|
|
||||||
assertThat(someDependency).isNotNull();
|
assertThat(someDependency).isNotNull();
|
||||||
return UUID.fromString(domainValue);
|
return UUID.fromString(domainValue);
|
||||||
|
|||||||
@@ -31,11 +31,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.convert;
|
package org.springframework.data.convert;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.data.convert.PropertyValueConverter.ValueConversionContext;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.data.mapping.PropertyPath;
|
import org.springframework.data.mapping.PropertyPath;
|
||||||
|
import org.springframework.data.mapping.context.SamplePersistentProperty;
|
||||||
|
import org.springframework.data.util.MethodInvocationRecorder;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,7 +55,33 @@ public class WhatWeWant {
|
|||||||
@Test
|
@Test
|
||||||
void converterConfig() {
|
void converterConfig() {
|
||||||
|
|
||||||
ConverterConfig converterConfig = null;
|
ConverterConfig<SamplePersistentProperty> converterConfig = new ConverterConfig();
|
||||||
|
|
||||||
|
// Arbitrary translations
|
||||||
|
converterConfig.registerConverter(Foo.class, Foo::getValue)
|
||||||
|
.writing((source, context) -> WhatWeWant.reverse(source)) // store reversed
|
||||||
|
.reading((source, context) -> WhatWeWant.reverse(source)); // restore order
|
||||||
|
|
||||||
|
converterConfig.registerConverter(it -> it.findAnnotation(Deprecated.class) != null)
|
||||||
|
.writing((source, context) -> WhatWeWant.reverse(source.toString()))
|
||||||
|
.reading((source, context) -> {
|
||||||
|
return context.read(WhatWeWant.reverse(source));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up on read
|
||||||
|
converterConfig.registerConverter(Foo.class, Foo::getValue)
|
||||||
|
.writingAsIs()
|
||||||
|
.reading((source, context) -> source.trim());
|
||||||
|
|
||||||
|
converterConfig.registerConverter(Foo.class, Foo::getAddress)
|
||||||
|
.writing((source, context) -> {
|
||||||
|
|
||||||
|
Map<Object, Object> map = new HashMap<>();
|
||||||
|
map.put("STREET", source.street.toUpperCase());
|
||||||
|
map.put("ZIP", context.write(source.zipCode));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
converterConfig.registerConverter(Foo.class, "value", new PropertyValueConverter() {
|
converterConfig.registerConverter(Foo.class, "value", new PropertyValueConverter() {
|
||||||
|
|
||||||
@@ -63,28 +97,185 @@ public class WhatWeWant {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ConverterConfig {
|
static String reverse(String source) {
|
||||||
|
return new StringBuilder(source).reverse().toString();
|
||||||
|
}
|
||||||
|
|
||||||
ConverterConfig registerConverter(Predicate<PersistentProperty<?>> filter, PropertyValueConverter<?,?, ? extends PropertyValueConverter.ValueConversionContext> converter) {
|
static class ConverterConfig<P extends PersistentProperty<P>> {
|
||||||
|
|
||||||
|
ConverterConfig registerConverter(Predicate<P> filter,
|
||||||
|
PropertyValueConverter<?, ?, ? extends ValueConversionContext<P>> converter) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConverterConfig registerConverter(Class type, String property, PropertyValueConverter<?,?, ? extends PropertyValueConverter.ValueConversionContext> converter) {
|
ConverterConfig registerConverter(Class type, String property,
|
||||||
|
PropertyValueConverter<?, ?, ? extends ValueConversionContext<P>> converter) {
|
||||||
PropertyPath.from(property, type);
|
PropertyPath.from(property, type);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a converter registration by pointing to a property of a domain type.
|
||||||
|
*
|
||||||
|
* @param <T> the domain type
|
||||||
|
* @param <S> the property type
|
||||||
|
* @param type the domain type to obtain the property from
|
||||||
|
* @param property a function to describe the property to be referenced. Usually a method handle to a getter.
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
<T, S> WritingConverterRegistrationBuilder<T, S, P> registerConverter(
|
||||||
|
Class<T> type, Function<T, S> property) {
|
||||||
|
|
||||||
|
String propertyName = MethodInvocationRecorder.forProxyOf(type)
|
||||||
|
.record(property)
|
||||||
|
.getPropertyPath()
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Cannot obtain property name!"));
|
||||||
|
|
||||||
|
return new WritingConverterRegistrationBuilder<T, S, P>(type, propertyName, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
<T, S> WritingConverterRegistrationBuilder<T, S, P> registerConverter(Predicate<P> predicate) {
|
||||||
|
return new WritingConverterRegistrationBuilder<T, S, P>(predicate, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to build up a fluent registration API starting on
|
||||||
|
* {@link ConverterConfig#registerConverter(Class, Function)}.
|
||||||
|
*
|
||||||
|
* @author Oliver Drotbohm
|
||||||
|
*/
|
||||||
|
static class WritingConverterRegistrationBuilder<T, S, P extends PersistentProperty<P>> {
|
||||||
|
|
||||||
|
private final Consumer<PropertyValueConverter> registration;
|
||||||
|
private final ConverterConfig config;
|
||||||
|
|
||||||
|
public WritingConverterRegistrationBuilder(Class<T> type, String property, ConverterConfig config) {
|
||||||
|
|
||||||
|
this.config = config;
|
||||||
|
this.registration = (converter) -> config.registerConverter(type, property, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WritingConverterRegistrationBuilder(Predicate<P> predicate, ConverterConfig config) {
|
||||||
|
|
||||||
|
this.config = config;
|
||||||
|
this.registration = (converter) -> config.registerConverter(predicate, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
<R> ReadingConverterRegistrationBuilder<T, S, S, P> writingAsIs() {
|
||||||
|
return writing((source, context) -> source);
|
||||||
|
}
|
||||||
|
|
||||||
|
<R> ReadingConverterRegistrationBuilder<T, S, R, P> writing(Function<S, R> writer) {
|
||||||
|
return writing((source, context) -> writer.apply(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes how to convert the domain property value into the database native property.
|
||||||
|
*
|
||||||
|
* @param <R> the type to be written to the database
|
||||||
|
* @param writer the property conversion to extract a value written to the database
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
<R> ReadingConverterRegistrationBuilder<T, S, R, P> writing(BiFunction<S, ValueConversionContext<P>, 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.
|
||||||
|
*
|
||||||
|
* @author Oliver Drotbohm
|
||||||
|
*/
|
||||||
|
static class ReadingConverterRegistrationBuilder<T, S, R, P extends PersistentProperty<P>> {
|
||||||
|
|
||||||
|
private WritingConverterRegistrationBuilder<T, S, P> origin;
|
||||||
|
private BiFunction<S, ValueConversionContext<P>, R> writer;
|
||||||
|
|
||||||
|
public ReadingConverterRegistrationBuilder(WritingConverterRegistrationBuilder<T, S, P> origin,
|
||||||
|
BiFunction<S, ValueConversionContext<P>, R> writer) {
|
||||||
|
this.origin = origin;
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConverterConfig<P> readingAsIs() {
|
||||||
|
return reading((source, context) -> (S) source);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConverterConfig<P> reading(Function<R, S> reader) {
|
||||||
|
return reading((source, context) -> reader.apply(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes how to read a database value into a domain object's property value.
|
||||||
|
*
|
||||||
|
* @param reader must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ConverterConfig<P> reading(BiFunction<R, ValueConversionContext<P>, S> reader) {
|
||||||
|
|
||||||
|
origin.registration.accept(new FunctionPropertyValueConverter(writer, reader));
|
||||||
|
|
||||||
|
return origin.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link PropertyValueConverter} that delegates conversion to the given {@link BiFunction}s.
|
||||||
|
*
|
||||||
|
* @author Oliver Drotbohm
|
||||||
|
*/
|
||||||
|
static class FunctionPropertyValueConverter<A, B, P extends PersistentProperty<P>>
|
||||||
|
implements PropertyValueConverter<A, B, ValueConversionContext<P>> {
|
||||||
|
|
||||||
|
private final BiFunction<A, ValueConversionContext<P>, B> writer;
|
||||||
|
private final BiFunction<B, ValueConversionContext<P>, A> reader;
|
||||||
|
|
||||||
|
public FunctionPropertyValueConverter(BiFunction<A, ValueConversionContext<P>, B> writer,
|
||||||
|
BiFunction<B, ValueConversionContext<P>, A> reader) {
|
||||||
|
this.writer = writer;
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public B domainToNative(A domainValue, ValueConversionContext<P> context) {
|
||||||
|
return writer.apply(domainValue, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public A nativeToDomain(B nativeValue, ValueConversionContext<P> context) {
|
||||||
|
return reader.apply(nativeValue, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Foo {
|
static class Foo {
|
||||||
String value;
|
String value;
|
||||||
|
Address address;
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SpecificValueConversionContext extends PropertyValueConverter.ValueConversionContext {
|
static class Address {
|
||||||
|
String street;
|
||||||
|
ZipCode zipCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ZipCode {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SpecificPropertyValueConverter<S,T> extends PropertyValueConverter<S,T,SpecificValueConversionContext> {}
|
interface SpecificValueConversionContext<P extends PersistentProperty<P>> extends ValueConversionContext<P> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpecificPropertyValueConverter<S, T>
|
||||||
|
extends PropertyValueConverter<S, T, SpecificValueConversionContext<SamplePersistentProperty>> {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -543,7 +543,8 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
|||||||
String value2;
|
String value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MyPropertyConverter implements PropertyValueConverter<Object,Object, ValueConversionContext> {
|
static class MyPropertyConverter
|
||||||
|
implements PropertyValueConverter<Object, Object, ValueConversionContext<SamplePersistentProperty>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object nativeToDomain(Object value, ValueConversionContext context) {
|
public Object nativeToDomain(Object value, ValueConversionContext context) {
|
||||||
@@ -556,7 +557,8 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MyPropertyConverterThatRequiresComponents implements PropertyValueConverter<Object,Object, ValueConversionContext> {
|
static class MyPropertyConverterThatRequiresComponents
|
||||||
|
implements PropertyValueConverter<Object, Object, ValueConversionContext<SamplePersistentProperty>> {
|
||||||
|
|
||||||
private final SomeDependency someDependency;
|
private final SomeDependency someDependency;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user