diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java index f783f7b323..9ea28fd603 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java @@ -693,7 +693,9 @@ public Object writeValue(@Nullable Object value, TypeInformation type) { if (getConversions().isSimpleType(value.getClass())) { - Optional> customWriteTarget = getConversions().getCustomWriteTarget(type.getType()); + Optional> customWriteTarget = getConversions().hasCustomWriteTarget(value.getClass(), type.getType()) + ? getConversions().getCustomWriteTarget(value.getClass(), type.getType()) + : getConversions().getCustomWriteTarget(type.getType()); if (customWriteTarget.isPresent()) { return getConversionService().convert(value, customWriteTarget.get()); } @@ -725,12 +727,15 @@ public Object writeValue(@Nullable Object value, TypeInformation type) { return writeCollection((Iterable) value, type); } - RelationalPersistentEntity persistentEntity = getMappingContext().getPersistentEntity(value.getClass()); + if (getMappingContext().hasPersistentEntityFor(value.getClass())) { - if (persistentEntity != null) { + RelationalPersistentEntity persistentEntity = getMappingContext().getPersistentEntity(value.getClass()); - Object id = persistentEntity.getIdentifierAccessor(value).getIdentifier(); - return writeValue(id, type); + if (persistentEntity != null) { + + Object id = persistentEntity.getIdentifierAccessor(value).getIdentifier(); + return writeValue(id, type); + } } return diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/MappingRelationalConverterUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/MappingRelationalConverterUnitTests.java index c8a88ab390..e30bdb10e1 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/MappingRelationalConverterUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/MappingRelationalConverterUnitTests.java @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.*; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -26,10 +25,13 @@ import java.util.Objects; import java.util.Set; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.GenericConverter; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.convert.ConverterBuilder; @@ -37,12 +39,14 @@ import org.springframework.data.convert.CustomConversions; import org.springframework.data.convert.CustomConversions.StoreConversions; import org.springframework.data.convert.ReadingConverter; +import org.springframework.data.convert.WritingConverter; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.projection.EntityProjection; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.domain.RowDocument; +import org.springframework.data.util.TypeInformation; /** * Unit tests for {@link MappingRelationalConverter}. @@ -210,6 +214,27 @@ void projectShouldReadProjectionWithNestedEntity() { assertThat(person.getAddresses()).extracting(Address::getStreet).hasSize(1).containsOnly("hwy"); } + @SuppressWarnings("unchecked") + @Test + void shouldApplyGenericTypeConverter() { + + converter = new MappingRelationalConverter(converter.getMappingContext(), + new CustomConversions(StoreConversions.NONE, List.of(GenericTypeConverter.INSTANCE))); + + var stringResult = (GenericClass) converter.writeValue("test", TypeInformation.of(GenericClass.class)); + var uuidResult = (GenericClass) converter.writeValue(UUID.fromString("1234567-8910-1112-1314-151617181920"), TypeInformation.of(GenericClass.class)); + + var stringGeneric = new GenericClass<>("test"); + var stringGenericResult = (String) converter.writeValue(stringGeneric, TypeInformation.of(String.class)); + var uuidGeneric = new GenericClass<>(UUID.fromString("1234567-8910-1112-1314-151617181920")); + var uuidGenericResult = (UUID) converter.writeValue(uuidGeneric, TypeInformation.of(UUID.class)); + + assertThat(stringResult.value()).isEqualTo("test"); + assertThat(uuidResult.value()).isEqualTo(UUID.fromString("1234567-8910-1112-1314-151617181920")); + assertThat(stringGenericResult).isEqualTo("test"); + assertThat(uuidGenericResult).isEqualTo(UUID.fromString("1234567-8910-1112-1314-151617181920")); + } + static class SimpleType { @Id String id; @@ -365,4 +390,31 @@ public MyEnum convert(String source) { } + @WritingConverter + enum GenericTypeConverter implements GenericConverter { + + INSTANCE; + + @Override + public Set getConvertibleTypes() { + return Set.of( + new ConvertiblePair(String.class, GenericClass.class), + new ConvertiblePair(UUID.class, GenericClass.class), + new ConvertiblePair(GenericClass.class, String.class), + new ConvertiblePair(GenericClass.class, UUID.class) + ); + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + if (targetType.getType() == GenericClass.class) + return new GenericClass<>(source); + + return ((GenericClass) source).value(); + } + + } + + public record GenericClass(T value) { } + }