Skip to content

Commit be52ec8

Browse files
committed
DataClassRowMapper exposes generic constructor parameters for type conversion
Closes gh-26881
1 parent cd9cad3 commit be52ec8

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/core/DataClassRowMapper.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,9 @@
2222

2323
import org.springframework.beans.BeanUtils;
2424
import org.springframework.beans.TypeConverter;
25+
import org.springframework.core.MethodParameter;
2526
import org.springframework.core.convert.ConversionService;
27+
import org.springframework.core.convert.TypeDescriptor;
2628
import org.springframework.lang.Nullable;
2729
import org.springframework.util.Assert;
2830

@@ -50,7 +52,7 @@ public class DataClassRowMapper<T> extends BeanPropertyRowMapper<T> {
5052
private String[] constructorParameterNames;
5153

5254
@Nullable
53-
private Class<?>[] constructorParameterTypes;
55+
private TypeDescriptor[] constructorParameterTypes;
5456

5557

5658
/**
@@ -75,9 +77,13 @@ protected void initialize(Class<T> mappedClass) {
7577
super.initialize(mappedClass);
7678

7779
this.mappedConstructor = BeanUtils.getResolvableConstructor(mappedClass);
78-
if (this.mappedConstructor.getParameterCount() > 0) {
80+
int paramCount = this.mappedConstructor.getParameterCount();
81+
if (paramCount > 0) {
7982
this.constructorParameterNames = BeanUtils.getParameterNames(this.mappedConstructor);
80-
this.constructorParameterTypes = this.mappedConstructor.getParameterTypes();
83+
this.constructorParameterTypes = new TypeDescriptor[paramCount];
84+
for (int i = 0; i < paramCount; i++) {
85+
this.constructorParameterTypes[i] = new TypeDescriptor(new MethodParameter(this.mappedConstructor, i));
86+
}
8187
}
8288
}
8389

@@ -90,8 +96,9 @@ protected T constructMappedInstance(ResultSet rs, TypeConverter tc) throws SQLEx
9096
args = new Object[this.constructorParameterNames.length];
9197
for (int i = 0; i < args.length; i++) {
9298
String name = underscoreName(this.constructorParameterNames[i]);
93-
Class<?> type = this.constructorParameterTypes[i];
94-
args[i] = tc.convertIfNecessary(getColumnValue(rs, rs.findColumn(name), type), type);
99+
TypeDescriptor td = this.constructorParameterTypes[i];
100+
Object value = getColumnValue(rs, rs.findColumn(name), td.getType());
101+
args[i] = tc.convertIfNecessary(value, td.getType(), td);
95102
}
96103
}
97104
else {

spring-jdbc/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -135,6 +135,7 @@ public Mock(MockType type) throws Exception {
135135
given(resultSet.getObject(anyInt(), any(Class.class))).willThrow(new SQLFeatureNotSupportedException());
136136
given(resultSet.getDate(3)).willReturn(new java.sql.Date(1221222L));
137137
given(resultSet.getBigDecimal(4)).willReturn(new BigDecimal("1234.56"));
138+
given(resultSet.getObject(4)).willReturn(new BigDecimal("1234.56"));
138139
given(resultSet.wasNull()).willReturn(type == MockType.TWO);
139140

140141
given(resultSetMetaData.getColumnCount()).willReturn(4);

spring-jdbc/src/test/java/org/springframework/jdbc/core/DataClassRowMapperTests.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,15 @@
1616

1717
package org.springframework.jdbc.core;
1818

19+
import java.math.BigDecimal;
20+
import java.util.Collections;
21+
import java.util.Date;
1922
import java.util.List;
2023

2124
import org.junit.jupiter.api.Test;
2225

2326
import org.springframework.jdbc.core.test.ConstructorPerson;
27+
import org.springframework.jdbc.core.test.ConstructorPersonWithGenerics;
2428

2529
import static org.assertj.core.api.Assertions.assertThat;
2630

@@ -42,4 +46,20 @@ public void testStaticQueryWithDataClass() throws Exception {
4246
mock.verifyClosed();
4347
}
4448

49+
@Test
50+
public void testStaticQueryWithDataClassAndGenerics() throws Exception {
51+
Mock mock = new Mock();
52+
List<ConstructorPersonWithGenerics> result = mock.getJdbcTemplate().query(
53+
"select name, age, birth_date, balance from people",
54+
new DataClassRowMapper<>(ConstructorPersonWithGenerics.class));
55+
assertThat(result.size()).isEqualTo(1);
56+
ConstructorPersonWithGenerics person = result.get(0);
57+
assertThat(person.name()).isEqualTo("Bubba");
58+
assertThat(person.age()).isEqualTo(22L);
59+
assertThat(person.birth_date()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L));
60+
assertThat(person.balance()).isEqualTo(Collections.singletonList(new BigDecimal("1234.56")));
61+
62+
mock.verifyClosed();
63+
}
64+
4565
}

spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPerson.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,13 +24,13 @@
2424
*/
2525
public class ConstructorPerson {
2626

27-
private String name;
27+
private final String name;
2828

29-
private long age;
29+
private final long age;
3030

31-
private java.util.Date birth_date;
31+
private final Date birth_date;
3232

33-
private BigDecimal balance;
33+
private final BigDecimal balance;
3434

3535

3636
public ConstructorPerson(String name, long age, Date birth_date, BigDecimal balance) {
@@ -42,19 +42,19 @@ public ConstructorPerson(String name, long age, Date birth_date, BigDecimal bala
4242

4343

4444
public String name() {
45-
return name;
45+
return this.name;
4646
}
4747

4848
public long age() {
49-
return age;
49+
return this.age;
5050
}
5151

5252
public Date birth_date() {
53-
return birth_date;
53+
return this.birth_date;
5454
}
5555

5656
public BigDecimal balance() {
57-
return balance;
57+
return this.balance;
5858
}
5959

6060
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.jdbc.core.test;
18+
19+
import java.math.BigDecimal;
20+
import java.util.Date;
21+
import java.util.List;
22+
23+
/**
24+
* @author Juergen Hoeller
25+
*/
26+
public class ConstructorPersonWithGenerics {
27+
28+
private final String name;
29+
30+
private final long age;
31+
32+
private final Date birth_date;
33+
34+
private final List<BigDecimal> balance;
35+
36+
37+
public ConstructorPersonWithGenerics(String name, long age, Date birth_date, List<BigDecimal> balance) {
38+
this.name = name;
39+
this.age = age;
40+
this.birth_date = birth_date;
41+
this.balance = balance;
42+
}
43+
44+
45+
public String name() {
46+
return this.name;
47+
}
48+
49+
public long age() {
50+
return this.age;
51+
}
52+
53+
public Date birth_date() {
54+
return this.birth_date;
55+
}
56+
57+
public List<BigDecimal> balance() {
58+
return this.balance;
59+
}
60+
61+
}

0 commit comments

Comments
 (0)