Skip to content

Commit b29e81f

Browse files
committed
Allow defaultBindHandler to be specified on Binder
Allow a `defaultBindHandler` to be specified on the `Binder` instance to save needing to pass it to each `bind` method call. Closes gh-17773
1 parent fb6568b commit b29e81f

File tree

2 files changed

+53
-3
lines changed
  • spring-boot-project/spring-boot/src
    • main/java/org/springframework/boot/context/properties/bind
    • test/java/org/springframework/boot/context/properties/bind

2 files changed

+53
-3
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public class Binder {
6565

6666
private final Consumer<PropertyEditorRegistry> propertyEditorInitializer;
6767

68+
private final BindHandler defaultBindHandler;
69+
6870
/**
6971
* Create a new {@link Binder} instance for the specified sources. A
7072
* {@link DefaultFormattingConversionService} will be used for all conversion.
@@ -116,12 +118,32 @@ public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolve
116118
*/
117119
public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver,
118120
ConversionService conversionService, Consumer<PropertyEditorRegistry> propertyEditorInitializer) {
121+
this(sources, placeholdersResolver, conversionService, propertyEditorInitializer, null);
122+
}
123+
124+
/**
125+
* Create a new {@link Binder} instance for the specified sources.
126+
* @param sources the sources used for binding
127+
* @param placeholdersResolver strategy to resolve any property placeholders
128+
* @param conversionService the conversion service to convert values (or {@code null}
129+
* to use {@link ApplicationConversionService})
130+
* @param propertyEditorInitializer initializer used to configure the property editors
131+
* that can convert values (or {@code null} if no initialization is required). Often
132+
* used to call {@link ConfigurableListableBeanFactory#copyRegisteredEditorsTo}.
133+
* @param defaultBindHandler the default bind handler to use if non is specified when
134+
* binding
135+
* @since 2.2.0
136+
*/
137+
public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver,
138+
ConversionService conversionService, Consumer<PropertyEditorRegistry> propertyEditorInitializer,
139+
BindHandler defaultBindHandler) {
119140
Assert.notNull(sources, "Sources must not be null");
120141
this.sources = sources;
121142
this.placeholdersResolver = (placeholdersResolver != null) ? placeholdersResolver : PlaceholdersResolver.NONE;
122143
this.conversionService = (conversionService != null) ? conversionService
123144
: ApplicationConversionService.getSharedInstance();
124145
this.propertyEditorInitializer = propertyEditorInitializer;
146+
this.defaultBindHandler = (defaultBindHandler != null) ? defaultBindHandler : BindHandler.DEFAULT;
125147
}
126148

127149
/**
@@ -254,7 +276,7 @@ public <T> T bindOrCreate(ConfigurationPropertyName name, Bindable<T> target, Bi
254276
private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, boolean create) {
255277
Assert.notNull(name, "Name must not be null");
256278
Assert.notNull(target, "Target must not be null");
257-
handler = (handler != null) ? handler : BindHandler.DEFAULT;
279+
handler = (handler != null) ? handler : this.defaultBindHandler;
258280
Context context = new Context();
259281
return bind(name, target, handler, context, false, create);
260282
}
@@ -439,8 +461,22 @@ private boolean containsNoDescendantOf(Iterable<ConfigurationPropertySource> sou
439461
* @return a {@link Binder} instance
440462
*/
441463
public static Binder get(Environment environment) {
442-
return new Binder(ConfigurationPropertySources.get(environment),
443-
new PropertySourcesPlaceholdersResolver(environment));
464+
return get(environment, null);
465+
}
466+
467+
/**
468+
* Create a new {@link Binder} instance from the specified environment.
469+
* @param environment the environment source (must have attached
470+
* {@link ConfigurationPropertySources})
471+
* @param defaultBindHandler the default bind handler to use if non is specified when
472+
* binding
473+
* @return a {@link Binder} instance
474+
* @since 2.2.0
475+
*/
476+
public static Binder get(Environment environment, BindHandler defaultBindHandler) {
477+
Iterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);
478+
PropertySourcesPlaceholdersResolver placeholdersResolver = new PropertySourcesPlaceholdersResolver(environment);
479+
return new Binder(sources, placeholdersResolver, null, null, defaultBindHandler);
444480
}
445481

446482
/**

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ void bindToJavaBeanShouldTriggerOnSuccess() {
210210
isA(JavaBean.class));
211211
}
212212

213+
@Test
214+
void bindWhenHasCustomDefultHandlerShouldTriggerOnSuccess() {
215+
this.sources.add(new MockConfigurationPropertySource("foo.value", "bar", "line1"));
216+
BindHandler handler = mock(BindHandler.class, Answers.CALLS_REAL_METHODS);
217+
Binder binder = new Binder(this.sources, null, null, null, handler);
218+
Bindable<JavaBean> target = Bindable.of(JavaBean.class);
219+
binder.bind("foo", target);
220+
InOrder inOrder = inOrder(handler);
221+
inOrder.verify(handler).onSuccess(eq(ConfigurationPropertyName.of("foo.value")), eq(Bindable.of(String.class)),
222+
any(), eq("bar"));
223+
inOrder.verify(handler).onSuccess(eq(ConfigurationPropertyName.of("foo")), eq(target), any(),
224+
isA(JavaBean.class));
225+
}
226+
213227
@Test
214228
void bindWhenHasMalformedDateShouldThrowException() {
215229
this.sources.add(new MockConfigurationPropertySource("foo", "2014-04-01T01:30:00.000-05:00"));

0 commit comments

Comments
 (0)