Skip to content

Commit 9c25b69

Browse files
committed
Improve performance of MapBinder by calculating items only once
Closes gh-44868
1 parent 859d074 commit 9c25b69

File tree

1 file changed

+21
-13
lines changed
  • spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind

1 file changed

+21
-13
lines changed

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -155,44 +155,56 @@ private class EntryBinder {
155155

156156
private final ResolvableType valueType;
157157

158+
private final Class<?> resolvedValueType;
159+
160+
private final boolean valueTreatedAsNestedMap;
161+
162+
private final Bindable<Object> bindableMapType;
163+
164+
private final Bindable<Object> bindableValueType;
165+
158166
EntryBinder(ConfigurationPropertyName root, Bindable<?> target, AggregateElementBinder elementBinder) {
159167
this.root = root;
160168
this.elementBinder = elementBinder;
161169
this.mapType = target.getType().asMap();
162170
this.keyType = this.mapType.getGeneric(0);
163171
this.valueType = this.mapType.getGeneric(1);
172+
this.resolvedValueType = this.valueType.resolve(Object.class);
173+
this.valueTreatedAsNestedMap = Object.class.equals(this.resolvedValueType);
174+
this.bindableMapType = Bindable.of(this.mapType);
175+
this.bindableValueType = Bindable.of(this.valueType);
164176
}
165177

166178
void bindEntries(ConfigurationPropertySource source, Map<Object, Object> map) {
167179
if (source instanceof IterableConfigurationPropertySource iterableSource) {
168180
for (ConfigurationPropertyName name : iterableSource) {
169-
Bindable<?> valueBindable = getValueBindable(name);
170181
ConfigurationPropertyName entryName = getEntryName(source, name);
171182
Object key = getContext().getConverter().convert(getKeyName(entryName), this.keyType);
183+
Bindable<?> valueBindable = getValueBindable(name);
172184
map.computeIfAbsent(key, (k) -> this.elementBinder.bind(entryName, valueBindable));
173185
}
174186
}
175187
}
176188

177189
private Bindable<?> getValueBindable(ConfigurationPropertyName name) {
178-
if (!this.root.isParentOf(name) && isValueTreatedAsNestedMap()) {
179-
return Bindable.of(this.mapType);
180-
}
181-
return Bindable.of(this.valueType);
190+
return (!isParentOf(name) && this.valueTreatedAsNestedMap) ? this.bindableMapType : this.bindableValueType;
182191
}
183192

184193
private ConfigurationPropertyName getEntryName(ConfigurationPropertySource source,
185194
ConfigurationPropertyName name) {
186-
Class<?> resolved = this.valueType.resolve(Object.class);
187-
if (Collection.class.isAssignableFrom(resolved) || this.valueType.isArray()) {
195+
if (Collection.class.isAssignableFrom(this.resolvedValueType) || this.valueType.isArray()) {
188196
return chopNameAtNumericIndex(name);
189197
}
190-
if (!this.root.isParentOf(name) && (isValueTreatedAsNestedMap() || !isScalarValue(source, name))) {
198+
if (!isParentOf(name) && (this.valueTreatedAsNestedMap || !isScalarValue(source, name))) {
191199
return name.chop(this.root.getNumberOfElements() + 1);
192200
}
193201
return name;
194202
}
195203

204+
private boolean isParentOf(ConfigurationPropertyName name) {
205+
return this.root.isParentOf(name);
206+
}
207+
196208
private ConfigurationPropertyName chopNameAtNumericIndex(ConfigurationPropertyName name) {
197209
int start = this.root.getNumberOfElements() + 1;
198210
int size = name.getNumberOfElements();
@@ -204,10 +216,6 @@ private ConfigurationPropertyName chopNameAtNumericIndex(ConfigurationPropertyNa
204216
return name;
205217
}
206218

207-
private boolean isValueTreatedAsNestedMap() {
208-
return Object.class.equals(this.valueType.resolve(Object.class));
209-
}
210-
211219
private boolean isScalarValue(ConfigurationPropertySource source, ConfigurationPropertyName name) {
212220
Class<?> resolved = this.valueType.resolve(Object.class);
213221
if (!resolved.getName().startsWith("java.lang") && !resolved.isEnum()) {

0 commit comments

Comments
 (0)