diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/BeanPropertyRowMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/BeanPropertyRowMapper.java index f1a591238..c7e78f1ba 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/BeanPropertyRowMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/BeanPropertyRowMapper.java @@ -389,7 +389,7 @@ public class BeanPropertyRowMapper implements RowMapper { */ @Nullable protected Object getColumnValue(Row row, int index, Class paramType) { - return row.get(index, paramType); + return row.getObject(index); } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/DataClassRowMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/DataClassRowMapper.java index 2baa12cd3..b5646acf1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/DataClassRowMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/DataClassRowMapper.java @@ -19,7 +19,9 @@ import java.lang.reflect.Constructor; import org.springframework.beans.BeanUtils; import org.springframework.beans.TypeConverter; +import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -43,7 +45,7 @@ public class DataClassRowMapper extends BeanPropertyRowMapper { private @Nullable String[] constructorParameterNames; - private @Nullable Class[] constructorParameterTypes; + private @Nullable TypeDescriptor[] constructorParameterTypes; /** * Create a new {@code DataClassRowMapper}. @@ -60,9 +62,13 @@ public class DataClassRowMapper extends BeanPropertyRowMapper { super.initialize(mappedClass); this.mappedConstructor = BeanUtils.getResolvableConstructor(mappedClass); - if (this.mappedConstructor.getParameterCount() > 0) { + int paramCount = this.mappedConstructor.getParameterCount(); + if (paramCount > 0) { this.constructorParameterNames = BeanUtils.getParameterNames(this.mappedConstructor); - this.constructorParameterTypes = this.mappedConstructor.getParameterTypes(); + this.constructorParameterTypes = new TypeDescriptor[paramCount]; + for (int i = 0; i < paramCount; i++) { + this.constructorParameterTypes[i] = new TypeDescriptor(new MethodParameter(this.mappedConstructor, i)); + } } } @@ -76,8 +82,9 @@ public class DataClassRowMapper extends BeanPropertyRowMapper { args = new Object[this.constructorParameterNames.length]; for (int i = 0; i < args.length; i++) { String name = underscoreName(this.constructorParameterNames[i]); - Class type = this.constructorParameterTypes[i]; - args[i] = tc.convertIfNecessary(getColumnValue(row, row.getColumnDefinitions().firstIndexOf(name), type), type); + TypeDescriptor td = this.constructorParameterTypes[i]; + Object value = getColumnValue(row, row.getColumnDefinitions().firstIndexOf(name), td.getType()); + args[i] = tc.convertIfNecessary(value, td.getType(), td); } } else { args = new Object[0]; diff --git a/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/core/cql/DataClassRowMapperUnitTests.kt b/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/core/cql/DataClassRowMapperUnitTests.kt index b6f255c3b..8bc7df7fd 100644 --- a/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/core/cql/DataClassRowMapperUnitTests.kt +++ b/spring-data-cassandra/src/test/kotlin/org/springframework/data/cassandra/core/cql/DataClassRowMapperUnitTests.kt @@ -40,8 +40,8 @@ class DataClassRowMapperUnitTests { val definitions = forColumns("firstname", "age") every { row.columnDefinitions } returns definitions - every { row.get(0, String::class.java) } returns "Walter" - every { row.get(1, Int::class.javaPrimitiveType) } returns 42 + every { row.getObject(0) } returns "Walter" + every { row.getObject(1) } returns 42 val rowMapper = DataClassRowMapper() val person = rowMapper.mapRow(row, 0) @@ -50,7 +50,24 @@ class DataClassRowMapperUnitTests { assertThat(person.age).isEqualTo(42) } + @Test // #1129 + fun createBeanWithGenericsFromRow() { + + val definitions = forColumns("firstname", "age") + + every { row.columnDefinitions } returns definitions + every { row.getObject(0) } returns "Walter" + every { row.getObject(1) } returns 42 + + val rowMapper = DataClassRowMapper() + val person = rowMapper.mapRow(row, 0) + + assertThat(person.firstname).isEqualTo("Walter") + assertThat(person.age).contains(42) + } + data class Person(val firstname: String, val age: Int) + data class PersonWithAgeList(val firstname: String, val age: List) private fun forColumns(vararg columns: String): ColumnDefinitions { @@ -59,7 +76,8 @@ class DataClassRowMapperUnitTests { for (column in columns) { val columnDefinition = Mockito.mock(ColumnDefinition::class.java) val columnIndex = index++ - Mockito.`when`(columnDefinition.name).thenReturn(CqlIdentifier.fromInternal(column)) + Mockito.`when`(columnDefinition.name) + .thenReturn(CqlIdentifier.fromInternal(column)) Mockito.`when`(definitions[columnIndex]).thenReturn(columnDefinition) Mockito.`when`(definitions.firstIndexOf(column)).thenReturn(columnIndex) }