Apply converters on simple value reads.

We now apply converters for simple value reads ensuring that e.g. Enum converters are applied.

Closes #1689
This commit is contained in:
Mark Paluch
2023-12-05 16:15:57 +01:00
parent 61a145178b
commit f6fcbd4e6a
2 changed files with 49 additions and 8 deletions

View File

@@ -307,7 +307,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
* @return the converted object, will never be {@literal null}.
*/
protected <S> S readAggregate(ConversionContext context, RowDocument document,
TypeInformation<? extends S> typeHint) {
TypeInformation<? extends S> typeHint) {
return readAggregate(context, new RowDocumentAccessor(document), typeHint);
}
@@ -321,7 +321,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
*/
@SuppressWarnings("unchecked")
protected <S> S readAggregate(ConversionContext context, RowDocumentAccessor documentAccessor,
TypeInformation<? extends S> typeHint) {
TypeInformation<? extends S> typeHint) {
Class<? extends S> rawType = typeHint.getType();
@@ -430,8 +430,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
}
@SuppressWarnings("ConstantConditions")
private <T> T doConvert(Object value, Class<? extends T> target,
@Nullable Class<? extends T> fallback) {
private <T> T doConvert(Object value, Class<? extends T> target, @Nullable Class<? extends T> fallback) {
if (getConversionService().canConvert(value.getClass(), target) || fallback == null) {
return getConversionService().convert(value, target);
@@ -504,7 +503,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
entity, contextualizing, context.getPath().getCurrentObject());
return new ConverterAwareSpELExpressionParameterValueProvider(context, evaluator, getConversionService(),
new ConvertingParameterValueProvider<>( parameterProvider::getParameterValue));
new ConvertingParameterValueProvider<>(parameterProvider::getParameterValue));
}
private <S> S populateProperties(ConversionContext context, RelationalPersistentEntity<S> entity,
@@ -641,6 +640,11 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
protected Object getPotentiallyConvertedSimpleRead(Object value, TypeInformation<?> type) {
Class<?> target = type.getType();
if (getConversions().hasCustomReadTarget(value.getClass(), target)) {
return getConversionService().convert(value, TypeDescriptor.forObject(value), createTypeDescriptor(type));
}
if (ClassUtils.isAssignableValue(target, value)) {
return value;
}
@@ -787,8 +791,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
@SuppressWarnings("unchecked")
@Override
public <S> S convert(Object source, TypeInformation<? extends S> typeHint,
ConversionContext context) {
public <S> S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context) {
Assert.notNull(source, "Source must not be null");
Assert.notNull(typeHint, "TypeInformation must not be null");
@@ -1196,7 +1199,8 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
}
}
private record PropertyTranslatingPropertyAccessor<T> (PersistentPropertyAccessor<T> delegate,
private record PropertyTranslatingPropertyAccessor<T>(
PersistentPropertyAccessor<T> delegate,
PersistentPropertyTranslator propertyTranslator) implements PersistentPropertyAccessor<T> {
static <T> PersistentPropertyAccessor<T> create(PersistentPropertyAccessor<T> delegate,

View File

@@ -17,6 +17,7 @@ package org.springframework.data.relational.core.conversion;
import static org.assertj.core.api.Assertions.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
@@ -26,13 +27,16 @@ import java.util.Objects;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceCreator;
import org.springframework.data.convert.ConverterBuilder;
import org.springframework.data.convert.ConverterBuilder.ConverterAware;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.CustomConversions.StoreConversions;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.projection.EntityProjection;
import org.springframework.data.relational.core.mapping.Column;
@@ -83,6 +87,20 @@ class MappingRelationalConverterUnitTests {
assertThat(result.name).isEqualTo("bar");
}
@Test
// GH-1689
void shouldApplySimpleTypeConverterSimpleType() {
converter = new MappingRelationalConverter(converter.getMappingContext(),
new CustomConversions(StoreConversions.NONE, List.of(MyEnumConverter.INSTANCE)));
RowDocument document = new RowDocument().append("my_enum", "one");
WithMyEnum result = converter.read(WithMyEnum.class, document);
assertThat(result.myEnum).isEqualTo(MyEnum.ONE);
}
@Test // GH-1586
void shouldReadNonstaticInner() {
@@ -328,4 +346,23 @@ class MappingRelationalConverterUnitTests {
String getStreet();
}
record WithMyEnum(MyEnum myEnum) {
}
enum MyEnum {
ONE, TWO,
}
@ReadingConverter
enum MyEnumConverter implements Converter<String, MyEnum> {
INSTANCE;
@Override
public MyEnum convert(String source) {
return MyEnum.valueOf(source.toUpperCase());
}
}
}