From 90103b0ae99361a21a21c5306fa85b1614a4e2fb Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 8 Apr 2022 13:00:31 +0200 Subject: [PATCH] Consistent support for direct column matches in DataClassRowMapper Closes gh-28243 --- .../jdbc/core/DataClassRowMapper.java | 15 +++++++++--- .../jdbc/core/AbstractRowMapperTests.java | 24 +++++++++++++++---- .../jdbc/core/BeanPropertyRowMapperTests.java | 11 +++++++++ .../jdbc/core/DataClassRowMapperTests.java | 10 ++++---- .../jdbc/core/test/AbstractPerson.java | 12 +++++----- .../test/ConstructorPersonWithGenerics.java | 10 ++++---- .../test/ConstructorPersonWithSetters.java | 16 ++++++------- .../jdbc/core/test/SpacePerson.java | 6 ++--- 8 files changed, 69 insertions(+), 35 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/DataClassRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/DataClassRowMapper.java index 7e09fcbe8919..274bfdfa0cbf 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/DataClassRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/DataClassRowMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -98,9 +98,18 @@ protected T constructMappedInstance(ResultSet rs, TypeConverter tc) throws SQLEx if (this.constructorParameterNames != null && this.constructorParameterTypes != null) { args = new Object[this.constructorParameterNames.length]; for (int i = 0; i < args.length; i++) { - String name = underscoreName(this.constructorParameterNames[i]); + String name = this.constructorParameterNames[i]; + int index; + try { + // Try direct name match first + index = rs.findColumn(lowerCaseName(name)); + } + catch (SQLException ex) { + // Try underscored name match instead + index = rs.findColumn(underscoreName(name)); + } TypeDescriptor td = this.constructorParameterTypes[i]; - Object value = getColumnValue(rs, rs.findColumn(name), td.getType()); + Object value = getColumnValue(rs, index, td.getType()); args[i] = tc.convertIfNecessary(value, td.getType(), td); } } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java index 1c0a86ffed97..cf9d5817b0c0 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/AbstractRowMapperTests.java @@ -20,6 +20,7 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; +import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; import java.sql.Timestamp; @@ -63,7 +64,7 @@ protected void verifyPerson(Person person) { protected void verifyPerson(ConcretePerson person) { assertThat(person.getName()).isEqualTo("Bubba"); assertThat(person.getAge()).isEqualTo(22L); - assertThat(person.getBirth_date()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); + assertThat(person.getBirthDate()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); assertThat(person.getBalance()).isEqualTo(new BigDecimal("1234.56")); verifyPersonViaBeanWrapper(person); } @@ -94,7 +95,14 @@ private void verifyPersonViaBeanWrapper(Object person) { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(person); assertThat(bw.getPropertyValue("name")).isEqualTo("Bubba"); assertThat(bw.getPropertyValue("age")).isEqualTo(22L); - assertThat((Date) bw.getPropertyValue("birth_date")).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); + Date birthDate; + if (bw.isReadableProperty("birth_date")) { + birthDate = (Date) bw.getPropertyValue("birth_date"); + } + else { + birthDate = (Date) bw.getPropertyValue("birthDate"); + } + assertThat(birthDate).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); assertThat(bw.getPropertyValue("balance")).isEqualTo(new BigDecimal("1234.56")); } @@ -107,7 +115,7 @@ protected void verifyPerson(EmailPerson person) { } - protected enum MockType {ONE, TWO, THREE} + protected enum MockType {ONE, TWO, THREE, FOUR} protected static class Mock { @@ -152,13 +160,19 @@ public Mock(MockType type) throws Exception { given(resultSetMetaData.getColumnLabel(1)).willReturn( type == MockType.THREE ? "Last Name" : "name"); given(resultSetMetaData.getColumnLabel(2)).willReturn("age"); - given(resultSetMetaData.getColumnLabel(3)).willReturn("birth_date"); + given(resultSetMetaData.getColumnLabel(3)).willReturn(type == MockType.FOUR ? "birthdate" :"birth_date"); given(resultSetMetaData.getColumnLabel(4)).willReturn("balance"); given(resultSetMetaData.getColumnLabel(5)).willReturn("e_mail"); given(resultSet.findColumn("name")).willReturn(1); given(resultSet.findColumn("age")).willReturn(2); - given(resultSet.findColumn("birth_date")).willReturn(3); + if (type == MockType.FOUR) { + given(resultSet.findColumn("birthdate")).willReturn(3); + } + else { + given(resultSet.findColumn("birthdate")).willThrow(new SQLException()); + given(resultSet.findColumn("birth_date")).willReturn(3); + } given(resultSet.findColumn("balance")).willReturn(4); given(resultSet.findColumn("e_mail")).willReturn(5); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java index 99e9eb416274..5ef1f57f8916 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java @@ -140,6 +140,17 @@ void queryWithSpaceInColumnNameAndLocalDate() throws Exception { mock.verifyClosed(); } + @Test + void queryWithDirectNameMatchOnBirthDate() throws Exception { + Mock mock = new Mock(MockType.FOUR); + List result = mock.getJdbcTemplate().query( + "select name, age, birthdate, balance from people", + new BeanPropertyRowMapper<>(ConcretePerson.class)); + assertThat(result).hasSize(1); + verifyPerson(result.get(0)); + mock.verifyClosed(); + } + @Test void queryWithUnderscoreInColumnNameAndPersonWithMultipleAdjacentUppercaseLettersInPropertyName() throws Exception { Mock mock = new Mock(); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/DataClassRowMapperTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/DataClassRowMapperTests.java index 48b0f7f03134..c612e5bcae63 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/DataClassRowMapperTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/DataClassRowMapperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ public void testStaticQueryWithDataClassAndGenerics() throws Exception { ConstructorPersonWithGenerics person = result.get(0); assertThat(person.name()).isEqualTo("Bubba"); assertThat(person.age()).isEqualTo(22L); - assertThat(person.birth_date()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); + assertThat(person.birthDate()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); assertThat(person.balance()).isEqualTo(Collections.singletonList(new BigDecimal("1234.56"))); mock.verifyClosed(); @@ -65,15 +65,15 @@ public void testStaticQueryWithDataClassAndGenerics() throws Exception { @Test public void testStaticQueryWithDataClassAndSetters() throws Exception { - Mock mock = new Mock(); + Mock mock = new Mock(MockType.FOUR); List result = mock.getJdbcTemplate().query( - "select name, age, birth_date, balance from people", + "select name, age, birthdate, balance from people", new DataClassRowMapper<>(ConstructorPersonWithSetters.class)); assertThat(result.size()).isEqualTo(1); ConstructorPersonWithSetters person = result.get(0); assertThat(person.name()).isEqualTo("BUBBA"); assertThat(person.age()).isEqualTo(22L); - assertThat(person.birth_date()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); + assertThat(person.birthDate()).usingComparator(Date::compareTo).isEqualTo(new java.util.Date(1221222L)); assertThat(person.balance()).isEqualTo(new BigDecimal("1234.56")); mock.verifyClosed(); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java index f2698d3073ac..b084644c6896 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/AbstractPerson.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ public abstract class AbstractPerson { private long age; - private Date birth_date; + private Date birthDate; public String getName() { @@ -46,12 +46,12 @@ public void setAge(long age) { this.age = age; } - public Date getBirth_date() { - return birth_date; + public Date getBirthDate() { + return birthDate; } - public void setBirth_date(Date birth_date) { - this.birth_date = birth_date; + public void setBirthDate(Date birthDate) { + this.birthDate = birthDate; } } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithGenerics.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithGenerics.java index 3ae8e271c810..289197b56392 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithGenerics.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithGenerics.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ public class ConstructorPersonWithGenerics { private final long age; - private final Date birth_date; + private final Date birthDate; private final List balance; @@ -37,7 +37,7 @@ public class ConstructorPersonWithGenerics { public ConstructorPersonWithGenerics(String name, long age, Date birth_date, List balance) { this.name = name; this.age = age; - this.birth_date = birth_date; + this.birthDate = birth_date; this.balance = balance; } @@ -50,8 +50,8 @@ public long age() { return this.age; } - public Date birth_date() { - return this.birth_date; + public Date birthDate() { + return this.birthDate; } public List balance() { diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithSetters.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithSetters.java index ef1feb9a324d..0776b5cc48ab 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithSetters.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/ConstructorPersonWithSetters.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,15 +28,15 @@ public class ConstructorPersonWithSetters { private long age; - private Date birth_date; + private Date birthDate; private BigDecimal balance; - public ConstructorPersonWithSetters(String name, long age, Date birth_date, BigDecimal balance) { + public ConstructorPersonWithSetters(String name, long age, Date birthDate, BigDecimal balance) { this.name = name.toUpperCase(); this.age = age; - this.birth_date = birth_date; + this.birthDate = birthDate; this.balance = balance; } @@ -49,8 +49,8 @@ public void setAge(long age) { this.age = age; } - public void setBirth_date(Date birth_date) { - this.birth_date = birth_date; + public void setBirthDate(Date birthDate) { + this.birthDate = birthDate; } public void setBalance(BigDecimal balance) { @@ -65,8 +65,8 @@ public long age() { return this.age; } - public Date birth_date() { - return this.birth_date; + public Date birthDate() { + return this.birthDate; } public BigDecimal balance() { diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/SpacePerson.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/SpacePerson.java index 8dc8875e15c8..2fc59db1b2e6 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/SpacePerson.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/test/SpacePerson.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,8 +60,8 @@ public BigDecimal getBalance() { return balance; } - public void setBalance(BigDecimal balanace) { - this.balance = balanace; + public void setBalance(BigDecimal balance) { + this.balance = balance; } }