Skip to content

Commit 4efae22

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 8d65932 commit 4efae22

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
@@ -955,7 +955,13 @@ private Object writeCollectionInternal(Collection<Object> source, ColumnType typ
955955
ColumnType componentType = type.getRequiredComponentType();
956956

957957
for (Object element : source) {
958-
converted.add(getWriteValue(element, componentType));
958+
959+
ColumnType elementType = componentType;
960+
if (elementType.getType() == Object.class) {
961+
elementType = getColumnTypeResolver().resolve(element);
962+
}
963+
964+
converted.add(getWriteValue(element, elementType));
959965
}
960966

961967
return converted;
@@ -969,7 +975,18 @@ private Object writeMapInternal(Map<Object, Object> source, ColumnType type) {
969975
ColumnType valueType = type.getRequiredMapValueType();
970976

971977
for (Entry<Object, Object> entry : source.entrySet()) {
972-
converted.put(getWriteValue(entry.getKey(), keyType), getWriteValue(entry.getValue(), valueType));
978+
979+
ColumnType elementKeyType = keyType;
980+
if (elementKeyType.getType() == Object.class) {
981+
elementKeyType = getColumnTypeResolver().resolve(entry.getKey());
982+
}
983+
984+
ColumnType elementValueType = valueType;
985+
if (elementValueType.getType() == Object.class) {
986+
elementValueType = getColumnTypeResolver().resolve(entry.getValue());
987+
}
988+
989+
converted.put(getWriteValue(entry.getKey(), elementKeyType), getWriteValue(entry.getValue(), elementValueType));
973990
}
974991

975992
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
@@ -29,6 +29,7 @@
2929
import java.util.LinkedHashMap;
3030
import java.util.List;
3131
import java.util.Map;
32+
import java.util.Set;
3233

3334
import org.junit.jupiter.api.BeforeEach;
3435
import org.junit.jupiter.api.Test;
@@ -213,6 +214,31 @@ void shouldWriteCompositeUdtPk() {
213214
+ "VALUES ('foo',{zip:'69469',city:'Weinheim',streetlines:['Heckenpfad','14']})");
214215
}
215216

217+
@Test // GH-1473
218+
void shouldWriteMapCorrectly() {
219+
220+
Manufacturer manufacturer = new Manufacturer("foo", "bar");
221+
AddressUserType addressUserType = prepareAddressUserType();
222+
223+
Map<Manufacturer, AddressUserType> value = Map.of(manufacturer, addressUserType);
224+
Map<?, ?> writeValue = (Map<?, ?>) converter.convertToColumnType(value);
225+
Map.Entry<?, ?> entry = writeValue.entrySet().iterator().next();
226+
227+
assertThat(entry.getKey()).isInstanceOf(UdtValue.class);
228+
assertThat(entry.getValue()).isInstanceOf(UdtValue.class);
229+
}
230+
231+
@Test // GH-1473
232+
void shouldWriteSetCorrectly() {
233+
234+
AddressUserType addressUserType = prepareAddressUserType();
235+
236+
Set<AddressUserType> value = Set.of(addressUserType);
237+
Set<?> writeValue = (Set<?>) converter.convertToColumnType(value);
238+
239+
assertThat(writeValue.iterator().next()).isInstanceOf(UdtValue.class);
240+
}
241+
216242
private static AddressUserType prepareAddressUserType() {
217243

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