Skip to content

Commit b751a81

Browse files
committed
Inspect collection elements during write value conversion.
We now deeply introspect collection and map elements when obtaining write values to ensure proper UDT and tuple conversions. Previously, collections containing UDT values did a pass-thru of values instead of applying UDT mapping. Closes #1473
1 parent ee56c6c commit b751a81

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,13 @@ private Object writeCollectionInternal(Collection<Object> source, ColumnType typ
968968
ColumnType componentType = type.getRequiredComponentType();
969969

970970
for (Object element : source) {
971-
converted.add(getWriteValue(element, componentType));
971+
972+
ColumnType elementType = componentType;
973+
if (elementType.getType() == Object.class) {
974+
elementType = getColumnTypeResolver().resolve(element);
975+
}
976+
977+
converted.add(getWriteValue(element, elementType));
972978
}
973979

974980
return converted;
@@ -982,7 +988,18 @@ private Object writeMapInternal(Map<Object, Object> source, ColumnType type) {
982988
ColumnType valueType = type.getRequiredMapValueType();
983989

984990
for (Entry<Object, Object> entry : source.entrySet()) {
985-
converted.put(getWriteValue(entry.getKey(), keyType), getWriteValue(entry.getValue(), valueType));
991+
992+
ColumnType elementKeyType = keyType;
993+
if (elementKeyType.getType() == Object.class) {
994+
elementKeyType = getColumnTypeResolver().resolve(entry.getKey());
995+
}
996+
997+
ColumnType elementValueType = valueType;
998+
if (elementValueType.getType() == Object.class) {
999+
elementValueType = getColumnTypeResolver().resolve(entry.getValue());
1000+
}
1001+
1002+
converted.put(getWriteValue(entry.getKey(), elementKeyType), getWriteValue(entry.getValue(), elementValueType));
9861003
}
9871004

9881005
return converted;

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.LinkedHashMap;
2626
import java.util.List;
2727
import java.util.Map;
28+
import java.util.Set;
2829

2930
import org.junit.jupiter.api.BeforeEach;
3031
import org.junit.jupiter.api.Test;
@@ -199,6 +200,31 @@ void shouldWriteCompositeUdtPk() {
199200
+ "VALUES ('foo',{zip:'69469',city:'Weinheim',streetlines:['Heckenpfad','14']})");
200201
}
201202

203+
@Test // GH-1473
204+
void shouldWriteMapCorrectly() {
205+
206+
Manufacturer manufacturer = new Manufacturer("foo", "bar");
207+
AddressUserType addressUserType = prepareAddressUserType();
208+
209+
Map<Manufacturer, AddressUserType> value = Map.of(manufacturer, addressUserType);
210+
Map<?, ?> writeValue = (Map<?, ?>) converter.convertToColumnType(value);
211+
Map.Entry<?, ?> entry = writeValue.entrySet().iterator().next();
212+
213+
assertThat(entry.getKey()).isInstanceOf(UdtValue.class);
214+
assertThat(entry.getValue()).isInstanceOf(UdtValue.class);
215+
}
216+
217+
@Test // GH-1473
218+
void shouldWriteSetCorrectly() {
219+
220+
AddressUserType addressUserType = prepareAddressUserType();
221+
222+
Set<AddressUserType> value = Set.of(addressUserType);
223+
Set<?> writeValue = (Set<?>) converter.convertToColumnType(value);
224+
225+
assertThat(writeValue.iterator().next()).isInstanceOf(UdtValue.class);
226+
}
227+
202228
private static AddressUserType prepareAddressUserType() {
203229

204230
AddressUserType addressUserType = new AddressUserType();

spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/StringBasedCassandraQueryUnitTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Arrays;
2727
import java.util.Collection;
2828
import java.util.HashSet;
29+
import java.util.Set;
2930

3031
import org.junit.jupiter.api.BeforeEach;
3132
import org.junit.jupiter.api.Test;
@@ -352,6 +353,27 @@ void bindsMappedUdtPropertyCorrectly() {
352353
assertThat(actual.getPositionalValues().get(0)).isInstanceOf(UdtValue.class);
353354
}
354355

356+
@Test // GH-1473
357+
void bindsCollectionOfMappedUdtPropertyCorrectly() {
358+
359+
UserDefinedType addressType = UserDefinedTypeBuilder.forName("address").withField("city", DataTypes.TEXT)
360+
.withField("country", DataTypes.TEXT).build();
361+
362+
when(userTypeResolver.resolveType(CqlIdentifier.fromCql("address"))).thenReturn(addressType);
363+
364+
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByMainAddress", Set.class);
365+
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
366+
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), Set.of(new AddressType())));
367+
368+
SimpleStatement actual = cassandraQuery.createQuery(accessor);
369+
370+
assertThat(actual.getQuery()).isEqualTo("SELECT * FROM person WHERE address=?;");
371+
assertThat(actual.getPositionalValues().get(0)).isInstanceOf(Set.class);
372+
373+
Set<?> set = (Set<?>) actual.getPositionalValues().get(0);
374+
assertThat(set.iterator().next()).isInstanceOf(UdtValue.class);
375+
}
376+
355377
@Test // DATACASS-172
356378
void bindsUdtValuePropertyCorrectly() {
357379

@@ -467,6 +489,9 @@ private interface SampleRepository extends Repository<Person, String> {
467489
@Query("SELECT * FROM person WHERE address=?0;")
468490
Person findByMainAddress(AddressType address);
469491

492+
@Query("SELECT * FROM person WHERE address=?0;")
493+
Person findByMainAddress(Set<AddressType> address);
494+
470495
@Query("SELECT * FROM person WHERE address=?0;")
471496
Person findByMainAddress(UdtValue UdtValue);
472497

0 commit comments

Comments
 (0)