From c885a15aeaac9db731a9224a2a102c1533d6b69f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 21 Sep 2020 16:34:02 -0700 Subject: [PATCH] Allow binding when 'is' method also exists Improve the `JavaBeanBinder` so that an bean that has both a `get` and `is` method can still be bound. Closes gh-23007 --- .../properties/bind/JavaBeanBinder.java | 12 +++-- .../properties/bind/JavaBeanBinderTests.java | 52 ++++++++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/JavaBeanBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/JavaBeanBinder.java index 07f8535368..91d73775d1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/JavaBeanBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/JavaBeanBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -140,9 +140,11 @@ class JavaBeanBinder implements DataObjectBinder { } } for (Method method : declaredMethods) { - addMethodIfPossible(method, "get", 0, BeanProperty::addGetter); addMethodIfPossible(method, "is", 0, BeanProperty::addGetter); } + for (Method method : declaredMethods) { + addMethodIfPossible(method, "get", 0, BeanProperty::addGetter); + } for (Method method : declaredMethods) { addMethodIfPossible(method, "set", 1, BeanProperty::addSetter); } @@ -280,11 +282,15 @@ class JavaBeanBinder implements DataObjectBinder { } void addGetter(Method getter) { - if (this.getter == null) { + if (this.getter == null || isBetterGetter(getter)) { this.getter = getter; } } + private boolean isBetterGetter(Method getter) { + return this.getter != null && this.getter.getName().startsWith("is"); + } + void addSetter(Method setter) { if (this.setter == null || isBetterSetter(setter)) { this.setter = setter; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java index 9bd77b27bb..9fe5fd1d4c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -540,6 +540,24 @@ class JavaBeanBinderTests { assertThat(bean.getProperty()).isEqualTo("test"); } + @Test // gh-23007 + void bindWhenBeanWithGetSetIsMethodsFoundUsesGetterThatMatchesSetter() { + MockConfigurationPropertySource source = new MockConfigurationPropertySource(); + source.put("test.names", "spring,boot"); + this.sources.add(source); + JavaBeanWithGetSetIs bean = this.binder.bind("test", Bindable.of(JavaBeanWithGetSetIs.class)).get(); + assertThat(bean.getNames()).containsExactly("spring", "boot"); + } + + @Test // gh-23007 + void bindWhenBeanWithGetIsMethodsFoundDoesNotUseIsGetter() { + MockConfigurationPropertySource source = new MockConfigurationPropertySource(); + source.put("test.names", "spring,boot"); + this.sources.add(source); + JavaBeanWithGetIs bean = this.binder.bind("test", Bindable.of(JavaBeanWithGetIs.class)).get(); + assertThat(bean.getNames()).containsExactly("spring", "boot"); + } + static class ExampleValueBean { private int intValue; @@ -1036,4 +1054,36 @@ class JavaBeanBinderTests { } + static class JavaBeanWithGetSetIs { + + private List names = new ArrayList<>(); + + List getNames() { + return this.names; + } + + void setNames(List names) { + this.names = names; + } + + boolean isNames() { + return !this.names.isEmpty(); + } + + } + + static class JavaBeanWithGetIs { + + private List names = new ArrayList<>(); + + boolean isNames() { + return !this.names.isEmpty(); + } + + List getNames() { + return this.names; + } + + } + }