Skip to content

Commit f28b200

Browse files
committed
Consider custom converters in ConversionContext before applying collection converters.
We now inspect whether custom conversions should be applied before reading a value into a Map or Collection to consider converters for Map-like and Collection-like types. Closes #1181
1 parent 4bac2a1 commit f28b200

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public MappingCassandraConverter(CassandraMappingContext mappingContext) {
144144
*/
145145
protected ConversionContext getConversionContext() {
146146

147-
return new ConversionContext(this::doReadRow, this::doReadTupleValue, this::doReadUdtValue,
147+
return new ConversionContext(getCustomConversions(), this::doReadRow, this::doReadTupleValue, this::doReadUdtValue,
148148
this::readCollectionOrArray, this::readMap, this::getPotentiallyConvertedSimpleRead);
149149
}
150150

@@ -1161,6 +1161,8 @@ protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, Cassandr
11611161
*/
11621162
protected static class ConversionContext {
11631163

1164+
private final org.springframework.data.convert.CustomConversions conversions;
1165+
11641166
private final ContainerValueConverter<Row> rowConverter;
11651167

11661168
private final ContainerValueConverter<TupleValue> tupleConverter;
@@ -1173,10 +1175,12 @@ protected static class ConversionContext {
11731175

11741176
private final ValueConverter<Object> elementConverter;
11751177

1176-
public ConversionContext(ContainerValueConverter<Row> rowConverter,
1178+
public ConversionContext(org.springframework.data.convert.CustomConversions conversions,
1179+
ContainerValueConverter<Row> rowConverter,
11771180
ContainerValueConverter<TupleValue> tupleConverter, ContainerValueConverter<UdtValue> udtConverter,
11781181
ContainerValueConverter<Collection<?>> collectionConverter, ContainerValueConverter<Map<?, ?>> mapConverter,
11791182
ValueConverter<Object> elementConverter) {
1183+
this.conversions = conversions;
11801184
this.rowConverter = rowConverter;
11811185
this.tupleConverter = tupleConverter;
11821186
this.udtConverter = udtConverter;
@@ -1197,6 +1201,10 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
11971201

11981202
Assert.notNull(typeHint, "TypeInformation must not be null");
11991203

1204+
if (conversions.hasCustomReadTarget(source.getClass(), typeHint.getType())) {
1205+
return (S) elementConverter.convert(source, typeHint);
1206+
}
1207+
12001208
if (source instanceof Collection) {
12011209

12021210
Class<?> rawType = typeHint.getType();

spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUnitTests.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@
3838
import java.time.ZoneOffset;
3939
import java.util.*;
4040

41+
import org.json.simple.JSONObject;
42+
import org.json.simple.parser.JSONParser;
43+
import org.json.simple.parser.ParseException;
4144
import org.junit.jupiter.api.BeforeEach;
4245
import org.junit.jupiter.api.Test;
4346

4447
import org.springframework.beans.factory.annotation.Value;
48+
import org.springframework.core.convert.converter.Converter;
4549
import org.springframework.data.annotation.Id;
4650
import org.springframework.data.annotation.ReadOnlyProperty;
4751
import org.springframework.data.annotation.Transient;
@@ -1445,4 +1449,53 @@ void readEmbeddedTypeWhenSourceDoesNotContainValues() {
14451449
WithNullableEmbeddedType target = mappingCassandraConverter.read(WithNullableEmbeddedType.class, source);
14461450
assertThat(target.nested).isNull();
14471451
}
1452+
1453+
@Test // DATACASS-1181
1454+
void shouldApplyCustomConverterToMapLikeType() {
1455+
1456+
CassandraCustomConversions conversions = new CassandraCustomConversions(
1457+
Arrays.asList(JsonToStringConverter.INSTANCE, StringToJsonConverter.INSTANCE));
1458+
1459+
this.mappingContext = new CassandraMappingContext();
1460+
this.mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
1461+
1462+
this.mappingCassandraConverter = new MappingCassandraConverter(mappingContext);
1463+
this.mappingCassandraConverter.setCustomConversions(conversions);
1464+
this.mappingCassandraConverter.afterPropertiesSet();
1465+
1466+
Row source = RowMockUtil.newRowMock(column("thejson", "{\"hello\":\"world\"}", DataTypes.TEXT));
1467+
1468+
TypeWithJsonObject target = mappingCassandraConverter.read(TypeWithJsonObject.class, source);
1469+
assertThat(target.theJson).isNotNull();
1470+
assertThat(target.theJson.get("hello")).isEqualTo("world");
1471+
}
1472+
1473+
static class TypeWithJsonObject {
1474+
1475+
JSONObject theJson;
1476+
}
1477+
1478+
enum StringToJsonConverter implements Converter<String, JSONObject> {
1479+
INSTANCE;
1480+
1481+
@Override
1482+
public JSONObject convert(String source) {
1483+
try {
1484+
return (JSONObject) new JSONParser().parse(source);
1485+
} catch (ParseException e) {
1486+
throw new RuntimeException(e);
1487+
}
1488+
}
1489+
1490+
}
1491+
1492+
enum JsonToStringConverter implements Converter<JSONObject, String> {
1493+
INSTANCE;
1494+
1495+
@Override
1496+
public String convert(JSONObject source) {
1497+
return source.toJSONString();
1498+
}
1499+
1500+
}
14481501
}

0 commit comments

Comments
 (0)