Skip to content

Commit 6788a11

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 be9cfc7 commit 6788a11

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
@@ -143,7 +143,7 @@ public MappingCassandraConverter(CassandraMappingContext mappingContext) {
143143
*/
144144
protected ConversionContext getConversionContext() {
145145

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

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

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

11651167
private final ContainerValueConverter<TupleValue> tupleConverter;
@@ -1172,10 +1174,12 @@ protected static class ConversionContext {
11721174

11731175
private final ValueConverter<Object> elementConverter;
11741176

1175-
public ConversionContext(ContainerValueConverter<Row> rowConverter,
1177+
public ConversionContext(org.springframework.data.convert.CustomConversions conversions,
1178+
ContainerValueConverter<Row> rowConverter,
11761179
ContainerValueConverter<TupleValue> tupleConverter, ContainerValueConverter<UdtValue> udtConverter,
11771180
ContainerValueConverter<Collection<?>> collectionConverter, ContainerValueConverter<Map<?, ?>> mapConverter,
11781181
ValueConverter<Object> elementConverter) {
1182+
this.conversions = conversions;
11791183
this.rowConverter = rowConverter;
11801184
this.tupleConverter = tupleConverter;
11811185
this.udtConverter = udtConverter;
@@ -1196,6 +1200,10 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
11961200

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

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

12011209
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)