Browse Source

Merge branch '6.2.x'

pull/34883/head
Sam Brannen 11 months ago
parent
commit
32e2c453b0
  1. 38
      spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java
  2. 148
      spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java

38
spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java

@ -26,12 +26,12 @@ import org.springframework.beans.factory.BeanInitializationException; @@ -26,12 +26,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.CompositePropertySource;
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;
@ -131,27 +131,23 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS @@ -131,27 +131,23 @@ 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)) {
PropertySourcesPropertyResolver resolver =
new PropertySourcesPropertyResolver(configurableEnvironment.getPropertySources());
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
propertyResolver = resolver;
PropertySource<?> environmentPropertySource;
if (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {
environmentPropertySource = new CompositePropertySource(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME,
configurableEnvironment.getPropertySources());
}
PropertyResolver propertyResolverToUse = propertyResolver;
this.propertySources.addLast(
new PropertySource<>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
@Override
public @Nullable String getProperty(String key) {
return propertyResolverToUse.getProperty(key);
}
}
);
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
public @Nullable Object getProperty(String key) {
return super.source.getProperty(key);
}
};
}
this.propertySources.addLast(environmentPropertySource);
}
try {
PropertySource<?> localPropertySource =

148
spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -19,11 +19,13 @@ package org.springframework.context.support; @@ -19,11 +19,13 @@ package org.springframework.context.support;
import java.util.Optional;
import java.util.Properties;
import org.junit.jupiter.api.Nested;
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.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -432,6 +434,150 @@ class PropertySourcesPlaceholderConfigurerTests { @@ -432,6 +434,150 @@ class PropertySourcesPlaceholderConfigurerTests {
}
/**
* Tests that use the escape character (or disable it) with nested placeholder
* resolution.
*/
@Nested
class EscapedNestedPlaceholdersTests {
@Test // gh-34861
void singleEscapeWithDefaultEscapeCharacter() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "admin")
.withProperty("my.property", "\\DOMAIN\\${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
ppc.postProcessBeanFactory(bf);
// \DOMAIN\${user.home} resolves to \DOMAIN${user.home} instead of \DOMAIN\admin
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("\\DOMAIN${user.home}");
}
@Test // gh-34861
void singleEscapeWithCustomEscapeCharacter() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "admin\\~${nested}")
.withProperty("my.property", "DOMAIN\\${user.home}\\~${enigma}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
// Set custom escape character.
ppc.setEscapeCharacter('~');
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("DOMAIN\\admin\\${nested}\\${enigma}");
}
@Test // gh-34861
void singleEscapeWithEscapeCharacterDisabled() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "admin\\")
.withProperty("my.property", "\\DOMAIN\\${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
// Disable escape character.
ppc.setEscapeCharacter(null);
ppc.postProcessBeanFactory(bf);
// \DOMAIN\${user.home} resolves to \DOMAIN\admin
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("\\DOMAIN\\admin\\");
}
@Test // gh-34861
void tripleEscapeWithDefaultEscapeCharacter() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "admin\\\\\\")
.withProperty("my.property", "DOMAIN\\\\\\${user.home}#${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("DOMAIN\\\\${user.home}#admin\\\\\\");
}
@Test // gh-34861
void tripleEscapeWithCustomEscapeCharacter() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "admin\\~${enigma}")
.withProperty("my.property", "DOMAIN~~~${user.home}#${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
// Set custom escape character.
ppc.setEscapeCharacter('~');
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("DOMAIN~~${user.home}#admin\\${enigma}");
}
@Test // gh-34861
void singleEscapeWithDefaultEscapeCharacterAndIgnoreUnresolvablePlaceholders() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "${enigma}")
.withProperty("my.property", "\\${DOMAIN}${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
ppc.setIgnoreUnresolvablePlaceholders(true);
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("${DOMAIN}${enigma}");
}
@Test // gh-34861
void singleEscapeWithCustomEscapeCharacterAndIgnoreUnresolvablePlaceholders() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "${enigma}")
.withProperty("my.property", "~${DOMAIN}\\${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
// Set custom escape character.
ppc.setEscapeCharacter('~');
ppc.setIgnoreUnresolvablePlaceholders(true);
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("${DOMAIN}\\${enigma}");
}
@Test // gh-34861
void tripleEscapeWithDefaultEscapeCharacterAndIgnoreUnresolvablePlaceholders() {
MockEnvironment env = new MockEnvironment()
.withProperty("user.home", "${enigma}")
.withProperty("my.property", "X:\\\\\\${DOMAIN}${user.home}");
DefaultListableBeanFactory bf = createBeanFactory();
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setEnvironment(env);
ppc.setIgnoreUnresolvablePlaceholders(true);
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("X:\\\\${DOMAIN}${enigma}");
}
private static DefaultListableBeanFactory createBeanFactory() {
BeanDefinition beanDefinition = genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.property}")
.getBeanDefinition();
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean",beanDefinition);
return bf;
}
}
private static class OptionalTestBean {
private Optional<String> name;

Loading…
Cancel
Save