mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Add possibility for mapping a property to an attribute with different name
Makes the Name annotation applicable on fields and takes this name when looking up the corresponding property. See gh-37105
This commit is contained in:
parent
500584f052
commit
2c1aced25f
@ -46,6 +46,7 @@ import org.springframework.core.ResolvableType;
|
|||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
|
* @author Lasse Wulff
|
||||||
*/
|
*/
|
||||||
class JavaBeanBinder implements DataObjectBinder {
|
class JavaBeanBinder implements DataObjectBinder {
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ class JavaBeanBinder implements DataObjectBinder {
|
|||||||
|
|
||||||
private <T> boolean bind(BeanSupplier<T> beanSupplier, DataObjectPropertyBinder propertyBinder,
|
private <T> boolean bind(BeanSupplier<T> beanSupplier, DataObjectPropertyBinder propertyBinder,
|
||||||
BeanProperty property) {
|
BeanProperty property) {
|
||||||
String propertyName = property.getName();
|
String propertyName = determinePropertyName(property);
|
||||||
ResolvableType type = property.getType();
|
ResolvableType type = property.getType();
|
||||||
Supplier<Object> value = property.getValue(beanSupplier);
|
Supplier<Object> value = property.getValue(beanSupplier);
|
||||||
Annotation[] annotations = property.getAnnotations();
|
Annotation[] annotations = property.getAnnotations();
|
||||||
@ -110,6 +111,15 @@ class JavaBeanBinder implements DataObjectBinder {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String determinePropertyName(BeanProperty property) {
|
||||||
|
return Arrays.stream((property.getAnnotations() != null) ? property.getAnnotations() : new Annotation[0])
|
||||||
|
.filter((annotation) -> annotation.annotationType() == Name.class)
|
||||||
|
.findFirst()
|
||||||
|
.map(Name.class::cast)
|
||||||
|
.map(Name::value)
|
||||||
|
.orElse(property.getName());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The properties of a bean that may be bound.
|
* The properties of a bean that may be bound.
|
||||||
*/
|
*/
|
||||||
|
@ -23,15 +23,16 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Annotation that can be used to specify the name when binding to an immutable property.
|
* Annotation that can be used to specify the name when binding to a property. This
|
||||||
* This annotation may be required when binding to names that clash with reserved language
|
* annotation may be required when binding to names that clash with reserved language
|
||||||
* keywords.
|
* keywords.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Lasse Wulff
|
||||||
* @since 2.4.0
|
* @since 2.4.0
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.PARAMETER)
|
@Target({ ElementType.FIELD, ElementType.PARAMETER })
|
||||||
@Documented
|
@Documented
|
||||||
public @interface Name {
|
public @interface Name {
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ import static org.assertj.core.api.Assertions.entry;
|
|||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
|
* @author Lasse Wulff
|
||||||
*/
|
*/
|
||||||
class JavaBeanBinderTests {
|
class JavaBeanBinderTests {
|
||||||
|
|
||||||
@ -74,6 +75,27 @@ class JavaBeanBinderTests {
|
|||||||
assertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);
|
assertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bindRenamedPropertyToClassBean() {
|
||||||
|
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||||
|
source.put("renamed.public", "alpha");
|
||||||
|
this.sources.add(source);
|
||||||
|
ExampleRenamedPropertyBean bean = this.binder.bind("renamed", Bindable.of(ExampleRenamedPropertyBean.class))
|
||||||
|
.get();
|
||||||
|
assertThat(bean.getExampleProperty()).isEqualTo("alpha");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bindRenamedPropertyToRecordBean() {
|
||||||
|
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||||
|
source.put("renamed.class", "alpha");
|
||||||
|
this.sources.add(source);
|
||||||
|
ExampleRenamedPropertyRecordBean bean = this.binder
|
||||||
|
.bind("renamed", Bindable.of(ExampleRenamedPropertyRecordBean.class))
|
||||||
|
.get();
|
||||||
|
assertThat(bean.exampleProperty()).isEqualTo("alpha");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bindToClassWhenHasNoPrefixShouldCreateBoundBean() {
|
void bindToClassWhenHasNoPrefixShouldCreateBoundBean() {
|
||||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||||
@ -648,6 +670,24 @@ class JavaBeanBinderTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ExampleRenamedPropertyBean {
|
||||||
|
|
||||||
|
@Name("public")
|
||||||
|
private String exampleProperty;
|
||||||
|
|
||||||
|
String getExampleProperty() {
|
||||||
|
return this.exampleProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExampleProperty(String exampleProperty) {
|
||||||
|
this.exampleProperty = exampleProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
record ExampleRenamedPropertyRecordBean(@Name("class") String exampleProperty) {
|
||||||
|
}
|
||||||
|
|
||||||
static class ExampleDefaultsBean {
|
static class ExampleDefaultsBean {
|
||||||
|
|
||||||
private int foo = 123;
|
private int foo = 123;
|
||||||
|
@ -26,11 +26,13 @@ import org.springframework.context.annotation.Import
|
|||||||
import org.springframework.test.context.support.TestPropertySourceUtils
|
import org.springframework.test.context.support.TestPropertySourceUtils
|
||||||
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.springframework.boot.context.properties.bind.Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ConfigurationProperties @ConfigurationProperties}-annotated beans.
|
* Tests for {@link ConfigurationProperties @ConfigurationProperties}-annotated beans.
|
||||||
*
|
*
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
|
* @author Lasse Wulff
|
||||||
*/
|
*/
|
||||||
class KotlinConfigurationPropertiesTests {
|
class KotlinConfigurationPropertiesTests {
|
||||||
|
|
||||||
@ -59,6 +61,22 @@ class KotlinConfigurationPropertiesTests {
|
|||||||
assertThat(this.context.getBean(LateInitProperties::class.java).inner.value).isEqualTo("alpha")
|
assertThat(this.context.getBean(LateInitProperties::class.java).inner.value).isEqualTo("alpha")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `renamed property can be bound`() {
|
||||||
|
this.context.register(EnableRenamedProperties::class.java)
|
||||||
|
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, "renamed.fun=beta")
|
||||||
|
this.context.refresh()
|
||||||
|
assertThat(this.context.getBean(RenamedProperties::class.java).bar).isEqualTo("beta")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `renamed property can be bound to late init attribute`() {
|
||||||
|
this.context.register(EnableRenamedLateInitProperties::class.java)
|
||||||
|
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, "renamed.var=beta")
|
||||||
|
this.context.refresh()
|
||||||
|
assertThat(this.context.getBean(RenamedLateInitProperties::class.java).bar).isEqualTo("beta")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `type with constructor bound lateinit property with default can be bound`() {
|
fun `type with constructor bound lateinit property with default can be bound`() {
|
||||||
this.context.register(EnableLateInitPropertiesWithDefault::class.java)
|
this.context.register(EnableLateInitPropertiesWithDefault::class.java)
|
||||||
@ -80,6 +98,21 @@ class KotlinConfigurationPropertiesTests {
|
|||||||
@ConfigurationProperties(prefix = "foo")
|
@ConfigurationProperties(prefix = "foo")
|
||||||
class BingProperties(@Suppress("UNUSED_PARAMETER") bar: String)
|
class BingProperties(@Suppress("UNUSED_PARAMETER") bar: String)
|
||||||
|
|
||||||
|
@ConfigurationProperties(prefix = "renamed")
|
||||||
|
class RenamedProperties(@Name("fun") val bar: String)
|
||||||
|
|
||||||
|
@EnableConfigurationProperties(RenamedProperties::class)
|
||||||
|
class EnableRenamedProperties
|
||||||
|
|
||||||
|
@ConfigurationProperties(prefix = "renamed")
|
||||||
|
class RenamedLateInitProperties{
|
||||||
|
@Name("var")
|
||||||
|
lateinit var bar: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableConfigurationProperties(RenamedLateInitProperties::class)
|
||||||
|
class EnableRenamedLateInitProperties
|
||||||
|
|
||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
class EnableConfigProperties
|
class EnableConfigProperties
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user