Restore support for non-EnumerablePropertySource in PropertySourcesPlaceholderConfigurer
Commit 3295289e17 fixed a number issues with placeholder resolution in
PropertySourcesPlaceholderConfigurer. However, in doing so, it replaced
a raw PropertySource with a CompositePropertySource which implements
EnumerablePropertySource.
Consequently, all property sources registered in the Environment must
now implement EnumerablePropertySource (which is not an actual
requirement). Otherwise, invocations of getPropertyNames() on the
CompositePropertySource result in an IllegalStateException, and that is
a breaking change which resulted in numerous build failures within the
Spring portfolio.
To address that regression, this commit introduces a private
ConfigurableEnvironmentPropertySource in
PropertySourcesPlaceholderConfigurer which is a "raw" PropertySource
that delegates directly to the PropertySources in a
ConfigurableEnvironment.
This commit also extracts the raw PropertySource for direct Environment
delegation into a new FallbackEnvironmentPropertySource.
See gh-17385
Closes gh-34861
This commit is contained in:
@@ -24,7 +24,6 @@ import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.PlaceholderConfigurerSupport;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.ConfigurablePropertyResolver;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -133,23 +132,10 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
||||
if (this.propertySources == null) {
|
||||
this.propertySources = new MutablePropertySources();
|
||||
if (this.environment != null) {
|
||||
PropertySource<?> environmentPropertySource;
|
||||
if (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {
|
||||
environmentPropertySource = new CompositePropertySource(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME,
|
||||
configurableEnvironment.getPropertySources());
|
||||
}
|
||||
else {
|
||||
// Fallback code path that should never apply in a regular scenario, since the
|
||||
// Environment in the ApplicationContext should always be a ConfigurableEnvironment.
|
||||
environmentPropertySource =
|
||||
new PropertySource<>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getProperty(String key) {
|
||||
return super.source.getProperty(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
PropertySource<?> environmentPropertySource =
|
||||
(this.environment instanceof ConfigurableEnvironment configurableEnvironment ?
|
||||
new ConfigurableEnvironmentPropertySource(configurableEnvironment) :
|
||||
new FallbackEnvironmentPropertySource(this.environment));
|
||||
this.propertySources.addLast(environmentPropertySource);
|
||||
}
|
||||
try {
|
||||
@@ -232,4 +218,75 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
||||
return this.appliedPropertySources;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Custom {@link PropertySource} that delegates to the
|
||||
* {@link ConfigurableEnvironment#getPropertySources() PropertySources} in a
|
||||
* {@link ConfigurableEnvironment}.
|
||||
* @since 6.2.7
|
||||
*/
|
||||
private static class ConfigurableEnvironmentPropertySource extends PropertySource<ConfigurableEnvironment> {
|
||||
|
||||
private final PropertySources propertySources;
|
||||
|
||||
|
||||
ConfigurableEnvironmentPropertySource(ConfigurableEnvironment environment) {
|
||||
super(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, environment);
|
||||
this.propertySources = environment.getPropertySources();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getProperty(String name) {
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
Object candidate = propertySource.getProperty(name);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
if (propertySource.containsProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConfigurableEnvironmentPropertySource {propertySources=" + this.propertySources + "}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback {@link PropertySource} that delegates to a raw {@link Environment}.
|
||||
* <p>Should never apply in a regular scenario, since the {@code Environment}
|
||||
* in an {@code ApplicationContext} should always be a {@link ConfigurableEnvironment}.
|
||||
* @since 6.2.7
|
||||
*/
|
||||
private static class FallbackEnvironmentPropertySource extends PropertySource<Environment> {
|
||||
|
||||
FallbackEnvironmentPropertySource(Environment environment) {
|
||||
super(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, environment);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getProperty(String name) {
|
||||
return super.source.getProperty(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FallbackEnvironmentPropertySource {environment=" + super.source + "}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user