diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java index 0b5f8505e..0c7d761b9 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java @@ -144,7 +144,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter */ protected ConversionContext getConversionContext() { - return new ConversionContext(this::doReadRow, this::doReadTupleValue, this::doReadUdtValue, + return new ConversionContext(getCustomConversions(), this::doReadRow, this::doReadTupleValue, this::doReadUdtValue, this::readCollectionOrArray, this::readMap, this::getPotentiallyConvertedSimpleRead); } @@ -1161,6 +1161,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter */ protected static class ConversionContext { + private final org.springframework.data.convert.CustomConversions conversions; + private final ContainerValueConverter rowConverter; private final ContainerValueConverter tupleConverter; @@ -1173,10 +1175,12 @@ public class MappingCassandraConverter extends AbstractCassandraConverter private final ValueConverter elementConverter; - public ConversionContext(ContainerValueConverter rowConverter, + public ConversionContext(org.springframework.data.convert.CustomConversions conversions, + ContainerValueConverter rowConverter, ContainerValueConverter tupleConverter, ContainerValueConverter udtConverter, ContainerValueConverter> collectionConverter, ContainerValueConverter> mapConverter, ValueConverter elementConverter) { + this.conversions = conversions; this.rowConverter = rowConverter; this.tupleConverter = tupleConverter; this.udtConverter = udtConverter; @@ -1197,6 +1201,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter Assert.notNull(typeHint, "TypeInformation must not be null"); + if (conversions.hasCustomReadTarget(source.getClass(), typeHint.getType())) { + return (S) elementConverter.convert(source, typeHint); + } + if (source instanceof Collection) { Class rawType = typeHint.getType(); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java index e8bbf9275..a06d9160a 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java @@ -38,10 +38,14 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.util.*; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import org.junit.jupiter.api.BeforeEach; 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.ReadOnlyProperty; import org.springframework.data.annotation.Transient; @@ -1445,4 +1449,53 @@ public class MappingCassandraConverterUnitTests { WithNullableEmbeddedType target = mappingCassandraConverter.read(WithNullableEmbeddedType.class, source); assertThat(target.nested).isNull(); } + + @Test // DATACASS-1181 + void shouldApplyCustomConverterToMapLikeType() { + + CassandraCustomConversions conversions = new CassandraCustomConversions( + Arrays.asList(JsonToStringConverter.INSTANCE, StringToJsonConverter.INSTANCE)); + + this.mappingContext = new CassandraMappingContext(); + this.mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); + + this.mappingCassandraConverter = new MappingCassandraConverter(mappingContext); + this.mappingCassandraConverter.setCustomConversions(conversions); + this.mappingCassandraConverter.afterPropertiesSet(); + + Row source = RowMockUtil.newRowMock(column("thejson", "{\"hello\":\"world\"}", DataTypes.TEXT)); + + TypeWithJsonObject target = mappingCassandraConverter.read(TypeWithJsonObject.class, source); + assertThat(target.theJson).isNotNull(); + assertThat(target.theJson.get("hello")).isEqualTo("world"); + } + + static class TypeWithJsonObject { + + JSONObject theJson; + } + + enum StringToJsonConverter implements Converter { + INSTANCE; + + @Override + public JSONObject convert(String source) { + try { + return (JSONObject) new JSONParser().parse(source); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + } + + enum JsonToStringConverter implements Converter { + INSTANCE; + + @Override + public String convert(JSONObject source) { + return source.toJSONString(); + } + + } }