DataClassRowMapper suppresses setter method calls for constructor-bound properties
Closes gh-26569
This commit is contained in:
parent
c45c46dad7
commit
4fe3ca1b82
|
@ -225,16 +225,40 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
|||
|
||||
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(mappedClass)) {
|
||||
if (pd.getWriteMethod() != null) {
|
||||
this.mappedFields.put(lowerCaseName(pd.getName()), pd);
|
||||
String underscoredName = underscoreName(pd.getName());
|
||||
if (!lowerCaseName(pd.getName()).equals(underscoredName)) {
|
||||
this.mappedFields.put(underscoredName, pd);
|
||||
String lowerCaseName = lowerCaseName(pd.getName());
|
||||
this.mappedFields.put(lowerCaseName, pd);
|
||||
String underscoreName = underscoreName(pd.getName());
|
||||
if (!lowerCaseName.equals(underscoreName)) {
|
||||
this.mappedFields.put(underscoreName, pd);
|
||||
}
|
||||
this.mappedProperties.add(pd.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified property from the mapped fields.
|
||||
* @param propertyName the property name (as used by property descriptors)
|
||||
* @since 5.3.9
|
||||
*/
|
||||
protected void suppressProperty(String propertyName) {
|
||||
if (this.mappedFields != null) {
|
||||
this.mappedFields.remove(lowerCaseName(propertyName));
|
||||
this.mappedFields.remove(underscoreName(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given name to lower case.
|
||||
* By default, conversions will happen within the US locale.
|
||||
* @param name the original name
|
||||
* @return the converted name
|
||||
* @since 4.2
|
||||
*/
|
||||
protected String lowerCaseName(String name) {
|
||||
return name.toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a name in camelCase to an underscored name in lower case.
|
||||
* Any upper case letters are converted to lower case with a preceding underscore.
|
||||
|
@ -261,17 +285,6 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given name to lower case.
|
||||
* By default, conversions will happen within the US locale.
|
||||
* @param name the original name
|
||||
* @return the converted name
|
||||
* @since 4.2
|
||||
*/
|
||||
protected String lowerCaseName(String name) {
|
||||
return name.toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the values for all columns in the current row.
|
||||
|
|
|
@ -80,6 +80,9 @@ public class DataClassRowMapper<T> extends BeanPropertyRowMapper<T> {
|
|||
int paramCount = this.mappedConstructor.getParameterCount();
|
||||
if (paramCount > 0) {
|
||||
this.constructorParameterNames = BeanUtils.getParameterNames(this.mappedConstructor);
|
||||
for (String name : this.constructorParameterNames) {
|
||||
suppressProperty(name);
|
||||
}
|
||||
this.constructorParameterTypes = new TypeDescriptor[paramCount];
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
this.constructorParameterTypes[i] = new TypeDescriptor(new MethodParameter(this.mappedConstructor, i));
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.jdbc.core.test.ConstructorPerson;
|
||||
import org.springframework.jdbc.core.test.ConstructorPersonWithGenerics;
|
||||
import org.springframework.jdbc.core.test.ConstructorPersonWithSetters;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -62,4 +63,20 @@ public class DataClassRowMapperTests extends AbstractRowMapperTests {
|
|||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaticQueryWithDataClassAndSetters() throws Exception {
|
||||
Mock mock = new Mock();
|
||||
List<ConstructorPersonWithSetters> result = mock.getJdbcTemplate().query(
|
||||
"select name, age, birth_date, 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.balance()).isEqualTo(new BigDecimal("1234.56"));
|
||||
|
||||
mock.verifyClosed();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ConstructorPersonWithSetters {
|
||||
|
||||
private String name;
|
||||
|
||||
private long age;
|
||||
|
||||
private Date birth_date;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
|
||||
public ConstructorPersonWithSetters(String name, long age, Date birth_date, BigDecimal balance) {
|
||||
this.name = name.toUpperCase();
|
||||
this.age = age;
|
||||
this.birth_date = birth_date;
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setAge(long age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public void setBirth_date(Date birth_date) {
|
||||
this.birth_date = birth_date;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public long age() {
|
||||
return this.age;
|
||||
}
|
||||
|
||||
public Date birth_date() {
|
||||
return this.birth_date;
|
||||
}
|
||||
|
||||
public BigDecimal balance() {
|
||||
return this.balance;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.jdbc.core.test.ConstructorPerson
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
|
||||
class KotlinDataClassRowMapperTests : AbstractRowMapperTests() {
|
||||
|
||||
@Test
|
||||
fun testStaticQueryWithDataClass() {
|
||||
val mock = Mock()
|
||||
val result = mock.jdbcTemplate.query(
|
||||
"select name, age, birth_date, balance from people",
|
||||
DataClassRowMapper(ConstructorPerson::class.java)
|
||||
)
|
||||
Assertions.assertThat(result.size).isEqualTo(1)
|
||||
verifyPerson(result[0])
|
||||
mock.verifyClosed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInitPropertiesAreNotOverridden() {
|
||||
val mock = Mock()
|
||||
val result = mock.jdbcTemplate.query(
|
||||
"select name, age, birth_date, balance from people",
|
||||
DataClassRowMapper(KotlinPerson::class.java)
|
||||
)
|
||||
Assertions.assertThat(result.size).isEqualTo(1)
|
||||
Assertions.assertThat(result[0].name).isEqualTo("Bubba appended by init")
|
||||
}
|
||||
|
||||
|
||||
data class KotlinPerson(var name: String, val age: Long, val birth_date: Date, val balance: BigDecimal) {
|
||||
init {
|
||||
name += " appended by init"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue