The org.springframework.boot.context.properties.bind.MapBinder#merge works in wrong result by deleting the cofniguration
See original GitHub issuethe code like this:
@Data
@ToString
@ConfigurationProperties(value = MonitorPluginConfiguration.PREFIX)
public class MonitorPluginConfiguration {
public static final String PREFIX = "monitor";
private Map<String, String> plugins;
}
the yaml configuration in nacos:
monitor:
plugins:
p1: 1
p2: 2
p3: 3
p4: 4
if i delete the key-value p4: 4
in the configuration from nacos ,the value for field MonitorPluginConfiguration#plugins will not be deleted.
the changed configuration in nacos after delete the the key-value p4: 4
monitor:
plugins:
p1: 1
p2: 2
p3: 3
I trace the code , i find the method in org.springframework.boot.context.properties.bind.MapBinder#merge
,
@Override
protected Map<Object, Object> merge(Supplier<Map<Object, Object>> existing, Map<Object, Object> additional) {
Map<Object, Object> existingMap = getExistingIfPossible(existing);
if (existingMap == null) {
return additional;
}
try {
existingMap.putAll(additional);
return copyIfPossible(existingMap);
}
catch (UnsupportedOperationException ex) {
Map<Object, Object> result = createNewMap(additional.getClass(), existingMap);
result.putAll(additional);
return result;
}
}
the parmater additional
value is {p1=1, p2=2, p3=3}
and the variable existingMap
value is {p1=1, p2=2, p3=3, p4=4}
for the code existingMap.putAll(additional)
, it will save the original value {p1=1, p2=2, p3=3, p4=4}
.
so the result is bad.
I think that it is good to execute existingMap.clear()
before executing the code existingMap.putAll(additional)
The code like this:
@Override
protected Map<Object, Object> merge(Supplier<Map<Object, Object>> existing, Map<Object, Object> additional) {
Map<Object, Object> existingMap = getExistingIfPossible(existing);
if (existingMap == null) {
return additional;
}
try {
existingMap.clear(); // add this line
existingMap.putAll(additional);
return copyIfPossible(existingMap);
}
catch (UnsupportedOperationException ex) {
Map<Object, Object> result = createNewMap(additional.getClass(), existingMap);
result.putAll(additional);
return result;
}
}
Issue Analytics
- State:
- Created a year ago
- Comments:6 (3 by maintainers)
Top Results From Across the Web
Failed to bind properties under 'xxx.yyy' to com.example.demo ...
This works well under Spring Boot 2.0.0 I have included a small sample application that reproduces the ... org.springframework.boot.context.properties.bind.
Read more >spring boot configuration properties not working - Stack Overflow
Based on OP's edit, here's a fully working solution. ... Using either of those. the properties bean should be set by the test....
Read more >Core Features - Spring
Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments.
Read more >Spring Boot, Maven and Eclipse Errors and TroubleShooting ...
Hal Browser and Spring Boot Actuator are not working! Configure 2.3.1. ... ClassCastException: org.springframework.boot.context.event.
Read more >HD93626: SWI - INCORRECT QUESTION WHEN DELETING ...
APAR status. Closed as unreproducible in next release. Error description. When deleting a configuration in SolidWorks, SmarTeam will ask a question, ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Thanks. From a Spring Boot perspective, this is working as designed and documented.
I believe the bug is in Spring Cloud. When they are rebinding configuration properties, an existing instance of
MonitorPluginConfiguration
should not be re-used. Instead, a fresh instance should be created and then have properties bound to it. This has been raised before but the Spring Cloud team declined it as a duplicate of https://github.com/spring-cloud/spring-cloud-commons/issues/818. You may want to raise the problem again as, IMO, it should be documented as a limitation at the least.@winjaychan Have you read the reference documentation that I linked to earlier? It describes the difference in behaviour for binding lists and maps. Lists are only ever bound from a single source (so they are cleared). Maps can be bound from multiple sources (so they are not cleared).
If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.