Ensure unresolvable placeholders can be ignored with @Value
Prior to this commit, if a PropertySourcesPlaceholderConfigurer bean was configured with its ignoreUnresolvablePlaceholders flag set to true, unresolvable placeholders in an @Value annotation were not ignored, resulting in a BeanCreationException for the bean using @Value. For example, given a property declared as `my.app.var = ${var}` without a corresponding `var` property declared, an attempt to resolve `@Value("${my.app.var}")` resulted in the following exception. java.lang.IllegalArgumentException: Could not resolve placeholder 'var' in value "${var}" This commit fixes this by modifying PropertySourcesPlaceholderConfigurer's postProcessBeanFactory(...) method so that a local PropertyResolver is created if the ignoreUnresolvablePlaceholders flag is set to true. The local PropertyResolver then enforces that flag, since the Environment in the ApplicationContext is most likely not configured with ignoreUnresolvablePlaceholders set to true. Closes gh-27947
This commit is contained in:
parent
d02d5adb54
commit
5c76ff5ef6
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,10 +24,12 @@ 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.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.ConfigurablePropertyResolver;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.core.env.PropertySourcesPropertyResolver;
|
||||
|
@ -57,6 +59,7 @@ import org.springframework.util.StringValueResolver;
|
|||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment
|
||||
* @see org.springframework.beans.factory.config.PlaceholderConfigurerSupport
|
||||
|
@ -129,12 +132,25 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
|||
if (this.propertySources == null) {
|
||||
this.propertySources = new MutablePropertySources();
|
||||
if (this.environment != null) {
|
||||
PropertyResolver propertyResolver = this.environment;
|
||||
// If the ignoreUnresolvablePlaceholders flag is set to true, we have to create a
|
||||
// local PropertyResolver to enforce that setting, since the Environment is most
|
||||
// likely not configured with ignoreUnresolvablePlaceholders set to true.
|
||||
// See https://github.com/spring-projects/spring-framework/issues/27947
|
||||
if (this.ignoreUnresolvablePlaceholders && (this.environment instanceof ConfigurableEnvironment)) {
|
||||
ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) this.environment;
|
||||
PropertySourcesPropertyResolver resolver =
|
||||
new PropertySourcesPropertyResolver(configurableEnvironment.getPropertySources());
|
||||
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
|
||||
propertyResolver = resolver;
|
||||
}
|
||||
PropertyResolver propertyResolverToUse = propertyResolver;
|
||||
this.propertySources.addLast(
|
||||
new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
|
||||
@Override
|
||||
@Nullable
|
||||
public String getProperty(String key) {
|
||||
return this.source.getProperty(key);
|
||||
return propertyResolverToUse.getProperty(key);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -21,9 +21,14 @@ import java.util.Properties;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
@ -40,8 +45,11 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.ge
|
|||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertySourcesPlaceholderConfigurer}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PropertySourcesPlaceholderConfigurerTests {
|
||||
|
@ -159,8 +167,11 @@ public class PropertySourcesPlaceholderConfigurerTests {
|
|||
|
||||
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
|
||||
//pc.setIgnoreUnresolvablePlaceholders(false); // the default
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(() ->
|
||||
ppc.postProcessBeanFactory(bf));
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> ppc.postProcessBeanFactory(bf))
|
||||
.havingCause()
|
||||
.isExactlyInstanceOf(IllegalArgumentException.class)
|
||||
.withMessage("Could not resolve placeholder 'my.name' in value \"${my.name}\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -177,6 +188,38 @@ public class PropertySourcesPlaceholderConfigurerTests {
|
|||
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("${my.name}");
|
||||
}
|
||||
|
||||
@Test
|
||||
// https://github.com/spring-projects/spring-framework/issues/27947
|
||||
public void ignoreUnresolvablePlaceholdersInAtValueAnnotation__falseIsDefault() {
|
||||
MockPropertySource mockPropertySource = new MockPropertySource("test");
|
||||
mockPropertySource.setProperty("my.key", "${enigma}");
|
||||
@SuppressWarnings("resource")
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.getEnvironment().getPropertySources().addLast(mockPropertySource);
|
||||
context.register(IgnoreUnresolvablePlaceholdersFalseConfig.class);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.havingCause()
|
||||
.isExactlyInstanceOf(IllegalArgumentException.class)
|
||||
.withMessage("Could not resolve placeholder 'enigma' in value \"${enigma}\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
// https://github.com/spring-projects/spring-framework/issues/27947
|
||||
public void ignoreUnresolvablePlaceholdersInAtValueAnnotation_true() {
|
||||
MockPropertySource mockPropertySource = new MockPropertySource("test");
|
||||
mockPropertySource.setProperty("my.key", "${enigma}");
|
||||
@SuppressWarnings("resource")
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.getEnvironment().getPropertySources().addLast(mockPropertySource);
|
||||
context.register(IgnoreUnresolvablePlaceholdersTrueConfig.class);
|
||||
context.refresh();
|
||||
|
||||
IgnoreUnresolvablePlaceholdersTrueConfig config = context.getBean(IgnoreUnresolvablePlaceholdersTrueConfig.class);
|
||||
assertThat(config.value).isEqualTo("${enigma}");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("serial")
|
||||
public void nestedUnresolvablePlaceholder() {
|
||||
|
@ -402,4 +445,30 @@ public class PropertySourcesPlaceholderConfigurerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class IgnoreUnresolvablePlaceholdersFalseConfig {
|
||||
|
||||
@Value("${my.key}")
|
||||
String value;
|
||||
|
||||
@Bean
|
||||
static PropertySourcesPlaceholderConfigurer pspc() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class IgnoreUnresolvablePlaceholdersTrueConfig {
|
||||
|
||||
@Value("${my.key}")
|
||||
String value;
|
||||
|
||||
@Bean
|
||||
static PropertySourcesPlaceholderConfigurer pspc() {
|
||||
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
|
||||
pspc.setIgnoreUnresolvablePlaceholders(true);
|
||||
return pspc;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue