Skip to content

Doc: ConfigurationClassParser's property source composition requires distinct (Resource)PropertySources names #28886

@djechelon

Description

@djechelon

Thanks to the team for taking the time.

Affects: 5.3.18 and main branch

Affected code

if (this.propertySourceNames.contains(name)) {
// We've already added a version, we need to extend it
PropertySource<?> existing = propertySources.get(name);
if (existing != null) {
PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
((ResourcePropertySource) propertySource).withResourceName() : propertySource);
if (existing instanceof CompositePropertySource) {
((CompositePropertySource) existing).addFirstPropertySource(newSource);
}
else {
if (existing instanceof ResourcePropertySource) {
existing = ((ResourcePropertySource) existing).withResourceName();
}
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(newSource);
composite.addPropertySource(existing);
propertySources.replace(name, composite);
}
return;
}
}

Discussion

The addPropertySource method is affected by a bug IMO where the effect of the if statement is reverted by the fact that PropertySources are hashed using their name property.

When code reaches the affected if-statement, it means that a PropertySource of name foo is already registered in the Spring context, and that PropertySource is assigned to the existing variable. The idea is to replace (L499) the old property source with name foo with the CompositePropertySource containing both.

The problem is, given that

  • CompositePropertySource holds a Set of PropertySources
  • PropertySources are hashed by their getName(), which is not extended currently
  • Both PropertySources to compose have same name

In the end, the second PropertySource won't be added and CompositePropertySource will hold only one PropertySource of name foo

Affected case

We found a problem when multiple teams work on different Java libraries, each declaring some property sources from classpath files.

In the end, we discovered that if two libraries hold the same env.yaml in different packages, but the associated PropertySource name is computed by the file name (not fully qualified path), two libraries define a PropertySource named env.yaml and clash.

We expect this to happen even if teams define any kind of MapPropertySource with the same non-unique name. We have implemented a workaround by using the fully qualified resource URL.

Suggested solution

Have CompositePropertySource use List than Set?

Test case

Not yet available

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: documentationA documentation task

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions