Browse Source

Let BeanPropertyRowMapper subclasses customize mapped names

Closes gh-32199
pull/32201/head
Juergen Hoeller 2 years ago
parent
commit
8ff102115a
  1. 33
      spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java
  2. 50
      spring-jdbc/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java

33
spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -250,11 +250,9 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(mappedClass)) { for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(mappedClass)) {
if (pd.getWriteMethod() != null) { if (pd.getWriteMethod() != null) {
String lowerCaseName = lowerCaseName(pd.getName()); Set<String> mappedNames = mappedNames(pd);
this.mappedProperties.put(lowerCaseName, pd); for (String mappedName : mappedNames) {
String underscoreName = underscoreName(pd.getName()); this.mappedProperties.put(mappedName, pd);
if (!lowerCaseName.equals(underscoreName)) {
this.mappedProperties.put(underscoreName, pd);
} }
this.mappedPropertyNames.add(pd.getName()); this.mappedPropertyNames.add(pd.getName());
} }
@ -273,6 +271,29 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
} }
} }
/**
* Determine the mapped names for the given property.
* <p>Subclasses may override this method to customize the mapped names,
* adding to or removing from the set determined by this base method
* (which returns the property name in lower-case and underscore-based
* form), or replacing the set completely.
* @param pd the property descriptor discovered on initialization
* @return a set of mapped names
* @since 6.1.4
* @see #lowerCaseName
* @see #underscoreName
*/
protected Set<String> mappedNames(PropertyDescriptor pd) {
Set<String> mappedNames = new HashSet<>(4);
String lowerCaseName = lowerCaseName(pd.getName());
mappedNames.add(lowerCaseName);
String underscoreName = underscoreName(pd.getName());
if (!lowerCaseName.equals(underscoreName)) {
mappedNames.add(underscoreName);
}
return mappedNames;
}
/** /**
* Convert the given name to lower case. * Convert the given name to lower case.
* <p>By default, conversions will happen within the US locale. * <p>By default, conversions will happen within the US locale.

50
spring-jdbc/src/test/java/org/springframework/jdbc/core/BeanPropertyRowMapperTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,12 @@
package org.springframework.jdbc.core; package org.springframework.jdbc.core;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Date;
import java.util.Set;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.CsvSource;
@ -155,6 +161,16 @@ class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
mock.verifyClosed(); mock.verifyClosed();
} }
@Test
void queryWithCustomNameMatchOnBirthDate() throws Exception {
Mock mock = new Mock(MockType.FOUR);
Person person = mock.getJdbcTemplate().queryForObject(
"select name, age, birthdate, balance from people",
new CustomBeanPropertyRowMapper());
verifyPerson(person);
mock.verifyClosed();
}
@Test @Test
void queryWithUnderscoreInColumnNameAndPersonWithMultipleAdjacentUppercaseLettersInPropertyName() throws Exception { void queryWithUnderscoreInColumnNameAndPersonWithMultipleAdjacentUppercaseLettersInPropertyName() throws Exception {
Mock mock = new Mock(); Mock mock = new Mock();
@ -179,4 +195,36 @@ class BeanPropertyRowMapperTests extends AbstractRowMapperTests {
assertThat(mapper.underscoreName(input)).isEqualTo(expected); assertThat(mapper.underscoreName(input)).isEqualTo(expected);
} }
@Retention(RetentionPolicy.RUNTIME)
@interface MyColumnName {
String value();
}
private static class CustomPerson extends Person {
@MyColumnName("birthdate")
public void setBirth_date(Date date) {
super.setBirth_date(date);
}
}
private static class CustomBeanPropertyRowMapper extends BeanPropertyRowMapper<CustomPerson> {
public CustomBeanPropertyRowMapper() {
super(CustomPerson.class);
}
@Override
protected Set<String> mappedNames(PropertyDescriptor pd) {
Set<String> mappedNames = super.mappedNames(pd);
MyColumnName customName = pd.getWriteMethod().getAnnotation(MyColumnName.class);
if (customName != null) {
mappedNames.add(customName.value());
}
return mappedNames;
}
}
} }

Loading…
Cancel
Save