Merge branch '6.2.x'
This commit is contained in:
@@ -103,6 +103,14 @@ for details.
|
||||
{spring-framework-api}++/objenesis/SpringObjenesis.html#IGNORE_OBJENESIS_PROPERTY_NAME++[`SpringObjenesis`]
|
||||
for details.
|
||||
|
||||
| `spring.placeholder.escapeCharacter.default`
|
||||
| The default escape character for property placeholder support. If not set, `'\'` will
|
||||
be used. Can be set to a custom escape character or an empty string to disable support
|
||||
for an escape character. The default escape character be explicitly overridden in
|
||||
`PropertySourcesPlaceholderConfigurer` and subclasses of `AbstractPropertyResolver`. See
|
||||
{spring-framework-api}++/core/env/AbstractPropertyResolver.html#DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME++[`AbstractPropertyResolver`]
|
||||
for details.
|
||||
|
||||
| `spring.test.aot.processing.failOnError`
|
||||
| A boolean flag that controls whether errors encountered during AOT processing in the
|
||||
_Spring TestContext Framework_ should result in an exception that fails the overall process.
|
||||
|
||||
@@ -101,8 +101,11 @@ NOTE: When configuring a `PropertySourcesPlaceholderConfigurer` using JavaConfig
|
||||
|
||||
Using the above configuration ensures Spring initialization failure if any `${}`
|
||||
placeholder could not be resolved. It is also possible to use methods like
|
||||
`setPlaceholderPrefix`, `setPlaceholderSuffix`, `setValueSeparator`, or
|
||||
`setEscapeCharacter` to customize placeholders.
|
||||
`setPlaceholderPrefix()`, `setPlaceholderSuffix()`, `setValueSeparator()`, or
|
||||
`setEscapeCharacter()` to customize the placeholder syntax. In addition, the default
|
||||
escape character can be changed or disabled globally by setting the
|
||||
`spring.placeholder.escapeCharacter.default` property via a JVM system property (or via
|
||||
the xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism).
|
||||
|
||||
NOTE: Spring Boot configures by default a `PropertySourcesPlaceholderConfigurer` bean that
|
||||
will get properties from `application.properties` and `application.yml` files.
|
||||
|
||||
@@ -314,7 +314,7 @@ Thus, marking it for lazy initialization will be ignored, and the
|
||||
|
||||
|
||||
[[beans-factory-placeholderconfigurer]]
|
||||
=== Example: The Class Name Substitution `PropertySourcesPlaceholderConfigurer`
|
||||
=== Example: Property Placeholder Substitution with `PropertySourcesPlaceholderConfigurer`
|
||||
|
||||
You can use the `PropertySourcesPlaceholderConfigurer` to externalize property values
|
||||
from a bean definition in a separate file by using the standard Java `Properties` format.
|
||||
@@ -341,7 +341,7 @@ with placeholder values is defined:
|
||||
|
||||
The example shows properties configured from an external `Properties` file. At runtime,
|
||||
a `PropertySourcesPlaceholderConfigurer` is applied to the metadata that replaces some
|
||||
properties of the DataSource. The values to replace are specified as placeholders of the
|
||||
properties of the `DataSource`. The values to replace are specified as placeholders of the
|
||||
form pass:q[`${property-name}`], which follows the Ant, log4j, and JSP EL style.
|
||||
|
||||
The actual values come from another file in the standard Java `Properties` format:
|
||||
@@ -355,10 +355,13 @@ jdbc.password=root
|
||||
----
|
||||
|
||||
Therefore, the `${jdbc.username}` string is replaced at runtime with the value, 'sa', and
|
||||
the same applies for other placeholder values that match keys in the properties file.
|
||||
The `PropertySourcesPlaceholderConfigurer` checks for placeholders in most properties and
|
||||
attributes of a bean definition. Furthermore, you can customize the placeholder prefix, suffix,
|
||||
default value separator, and escape character.
|
||||
the same applies for other placeholder values that match keys in the properties file. The
|
||||
`PropertySourcesPlaceholderConfigurer` checks for placeholders in most properties and
|
||||
attributes of a bean definition. Furthermore, you can customize the placeholder prefix,
|
||||
suffix, default value separator, and escape character. In addition, the default escape
|
||||
character can be changed or disabled globally by setting the
|
||||
`spring.placeholder.escapeCharacter.default` property via a JVM system property (or via
|
||||
the xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism).
|
||||
|
||||
With the `context` namespace, you can configure property placeholders
|
||||
with a dedicated configuration element. You can provide one or more locations as a
|
||||
|
||||
@@ -190,7 +190,7 @@ NOTE: If you use Spring Boot, you should probably use
|
||||
instead of `@Value` annotations.
|
||||
|
||||
As an alternative, you can customize the property placeholder prefix by declaring the
|
||||
following configuration bean:
|
||||
following `PropertySourcesPlaceholderConfigurer` bean:
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@@ -200,8 +200,10 @@ following configuration bean:
|
||||
}
|
||||
----
|
||||
|
||||
You can customize existing code (such as Spring Boot actuators or `@LocalServerPort`)
|
||||
that uses the `${...}` syntax, with configuration beans, as the following example shows:
|
||||
You can support components (such as Spring Boot actuators or `@LocalServerPort`) that use
|
||||
the standard `${...}` syntax alongside components that use the custom `%{...}` syntax by
|
||||
declaring multiple `PropertySourcesPlaceholderConfigurer` beans, as the following example
|
||||
shows:
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
@@ -215,6 +217,9 @@ that uses the `${...}` syntax, with configuration beans, as the following exampl
|
||||
fun defaultPropertyConfigurer() = PropertySourcesPlaceholderConfigurer()
|
||||
----
|
||||
|
||||
In addition, the default escape character can be changed or disabled globally by setting
|
||||
the `spring.placeholder.escapeCharacter.default` property via a JVM system property (or
|
||||
via the xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism).
|
||||
|
||||
|
||||
[[checked-exceptions]]
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.core.env.AbstractPropertyResolver;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
@@ -86,6 +87,7 @@ import org.springframework.util.SystemPropertyUtils;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see PropertyPlaceholderConfigurer
|
||||
* @see org.springframework.context.support.PropertySourcesPlaceholderConfigurer
|
||||
@@ -102,7 +104,11 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
/** Default value separator: {@value}. */
|
||||
public static final String DEFAULT_VALUE_SEPARATOR = SystemPropertyUtils.VALUE_SEPARATOR;
|
||||
|
||||
/** Default escape character: {@code '\'}. */
|
||||
/**
|
||||
* Default escape character: {@code '\'}.
|
||||
* @since 6.2
|
||||
* @see AbstractPropertyResolver#getDefaultEscapeCharacter()
|
||||
*/
|
||||
public static final Character DEFAULT_ESCAPE_CHARACTER = SystemPropertyUtils.ESCAPE_CHARACTER;
|
||||
|
||||
|
||||
@@ -115,8 +121,10 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR}. */
|
||||
protected @Nullable String valueSeparator = DEFAULT_VALUE_SEPARATOR;
|
||||
|
||||
/** Defaults to {@link #DEFAULT_ESCAPE_CHARACTER}. */
|
||||
protected @Nullable Character escapeCharacter = DEFAULT_ESCAPE_CHARACTER;
|
||||
/**
|
||||
* The default is determined by {@link AbstractPropertyResolver#getDefaultEscapeCharacter()}.
|
||||
*/
|
||||
protected @Nullable Character escapeCharacter = AbstractPropertyResolver.getDefaultEscapeCharacter();
|
||||
|
||||
protected boolean trimValues = false;
|
||||
|
||||
@@ -160,6 +168,7 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
* {@linkplain #setPlaceholderPrefix(String) placeholder prefix} and the
|
||||
* {@linkplain #setValueSeparator(String) value separator}, or {@code null}
|
||||
* if no escaping should take place.
|
||||
* <p>The default is determined by {@link AbstractPropertyResolver#getDefaultEscapeCharacter()}.
|
||||
* @since 6.2
|
||||
*/
|
||||
public void setEscapeCharacter(@Nullable Character escapeCharacter) {
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
|
||||
package org.springframework.context.support;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -37,7 +40,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.AbstractPropertyResolver;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
@@ -47,12 +52,15 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.testfixture.env.MockPropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.util.PlaceholderResolutionException;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
|
||||
import static org.springframework.core.env.AbstractPropertyResolver.DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertySourcesPlaceholderConfigurer}.
|
||||
@@ -667,6 +675,108 @@ class PropertySourcesPlaceholderConfigurerTests {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that globally set the default escape character (or disable it) and
|
||||
* rely on nested placeholder resolution.
|
||||
*/
|
||||
@Nested
|
||||
class GlobalDefaultEscapeCharacterTests {
|
||||
|
||||
private static final Field defaultEscapeCharacterField =
|
||||
ReflectionUtils.findField(AbstractPropertyResolver.class, "defaultEscapeCharacter");
|
||||
|
||||
static {
|
||||
ReflectionUtils.makeAccessible(defaultEscapeCharacterField);
|
||||
}
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void resetStateBeforeEachTest() {
|
||||
resetState();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void resetState() {
|
||||
ReflectionUtils.setField(defaultEscapeCharacterField, null, Character.MIN_VALUE);
|
||||
setSpringProperty(null);
|
||||
}
|
||||
|
||||
|
||||
@Test // gh-34865
|
||||
void defaultEscapeCharacterSetToXyz() {
|
||||
setSpringProperty("XYZ");
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(PropertySourcesPlaceholderConfigurer::new)
|
||||
.withMessage("Value [XYZ] for property [%s] must be a single character or an empty string",
|
||||
DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test // gh-34865
|
||||
void defaultEscapeCharacterDisabled() {
|
||||
setSpringProperty("");
|
||||
|
||||
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);
|
||||
|
||||
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("\\DOMAIN\\admin");
|
||||
}
|
||||
|
||||
@Test // gh-34865
|
||||
void defaultEscapeCharacterSetToBackslash() {
|
||||
setSpringProperty("\\");
|
||||
|
||||
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-34865
|
||||
void defaultEscapeCharacterSetToTilde() {
|
||||
setSpringProperty("~");
|
||||
|
||||
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);
|
||||
ppc.postProcessBeanFactory(bf);
|
||||
|
||||
assertThat(bf.getBean(TestBean.class).getName()).isEqualTo("DOMAIN\\admin\\${nested}\\${enigma}");
|
||||
}
|
||||
|
||||
private static void setSpringProperty(String value) {
|
||||
SpringProperties.setProperty(DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME, value);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
@@ -37,10 +38,51 @@ import org.springframework.util.SystemPropertyUtils;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
|
||||
|
||||
/**
|
||||
* JVM system property used to change the <em>default</em> escape character
|
||||
* for property placeholder support: {@value}.
|
||||
* <p>To configure a custom escape character, supply a string containing a
|
||||
* single character (other than {@link Character#MIN_VALUE}). For example,
|
||||
* supplying the following JVM system property via the command line sets the
|
||||
* default escape character to {@code '@'}.
|
||||
* <pre style="code">-Dspring.placeholder.escapeCharacter.default=@</pre>
|
||||
* <p>To disable escape character support, set the value to an empty string
|
||||
* — for example, by supplying the following JVM system property via
|
||||
* the command line.
|
||||
* <pre style="code">-Dspring.placeholder.escapeCharacter.default=</pre>
|
||||
* <p>If the property is not set, {@code '\'} will be used as the default
|
||||
* escape character.
|
||||
* <p>May alternatively be configured via a
|
||||
* {@link org.springframework.core.SpringProperties spring.properties} file
|
||||
* in the root of the classpath.
|
||||
* @since 6.2.7
|
||||
* @see #getDefaultEscapeCharacter()
|
||||
*/
|
||||
public static final String DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME =
|
||||
"spring.placeholder.escapeCharacter.default";
|
||||
|
||||
/**
|
||||
* Since {@code null} is a valid value for {@link #defaultEscapeCharacter},
|
||||
* this constant provides a way to represent an undefined (or not yet set)
|
||||
* value. Consequently, {@link #getDefaultEscapeCharacter()} prevents the use
|
||||
* of {@link Character#MIN_VALUE} as the actual escape character.
|
||||
* @since 6.2.7
|
||||
*/
|
||||
static final Character UNDEFINED_ESCAPE_CHARACTER = Character.MIN_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* Cached value for the default escape character.
|
||||
* @since 6.2.7
|
||||
*/
|
||||
static volatile @Nullable Character defaultEscapeCharacter = UNDEFINED_ESCAPE_CHARACTER;
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private volatile @Nullable ConfigurableConversionService conversionService;
|
||||
@@ -57,7 +99,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
|
||||
private @Nullable String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
|
||||
|
||||
private @Nullable Character escapeCharacter = SystemPropertyUtils.ESCAPE_CHARACTER;
|
||||
private @Nullable Character escapeCharacter = getDefaultEscapeCharacter();
|
||||
|
||||
private final Set<String> requiredProperties = new LinkedHashSet<>();
|
||||
|
||||
@@ -119,9 +161,8 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>The default is {@code '\'}.
|
||||
* <p>The default is determined by {@link #getDefaultEscapeCharacter()}.
|
||||
* @since 6.2
|
||||
* @see SystemPropertyUtils#ESCAPE_CHARACTER
|
||||
*/
|
||||
@Override
|
||||
public void setEscapeCharacter(@Nullable Character escapeCharacter) {
|
||||
@@ -279,4 +320,59 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
*/
|
||||
protected abstract @Nullable String getPropertyAsRawString(String key);
|
||||
|
||||
|
||||
/**
|
||||
* Get the default {@linkplain #setEscapeCharacter(Character) escape character}
|
||||
* to use when parsing strings for property placeholder resolution.
|
||||
* <p>This method attempts to retrieve the default escape character configured
|
||||
* via the {@value #DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME} JVM system
|
||||
* property or Spring property.
|
||||
* <p>Falls back to {@code '\'} if the property has not been set.
|
||||
* @return the configured default escape character, {@code null} if escape character
|
||||
* support has been disabled, or {@code '\'} if the property has not been set
|
||||
* @throws IllegalArgumentException if the property is configured with an
|
||||
* invalid value, such as {@link Character#MIN_VALUE} or a string containing
|
||||
* more than one character
|
||||
* @since 6.2.7
|
||||
* @see #DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME
|
||||
* @see SystemPropertyUtils#ESCAPE_CHARACTER
|
||||
* @see SpringProperties
|
||||
*/
|
||||
public static @Nullable Character getDefaultEscapeCharacter() throws IllegalArgumentException {
|
||||
Character escapeCharacter = defaultEscapeCharacter;
|
||||
if (UNDEFINED_ESCAPE_CHARACTER.equals(escapeCharacter)) {
|
||||
String value = SpringProperties.getProperty(DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME);
|
||||
if (value != null) {
|
||||
if (value.isEmpty()) {
|
||||
// Disable escape character support by default.
|
||||
escapeCharacter = null;
|
||||
}
|
||||
else if (value.length() == 1) {
|
||||
try {
|
||||
// Use custom default escape character.
|
||||
escapeCharacter = value.charAt(0);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Failed to process value [%s] for property [%s]: %s"
|
||||
.formatted(value, DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME, ex.getMessage()), ex);
|
||||
}
|
||||
Assert.isTrue(!escapeCharacter.equals(Character.MIN_VALUE),
|
||||
() -> "Value for property [%s] must not be Character.MIN_VALUE"
|
||||
.formatted(DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME));
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"Value [%s] for property [%s] must be a single character or an empty string"
|
||||
.formatted(value, DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use standard default value for the escape character.
|
||||
escapeCharacter = SystemPropertyUtils.ESCAPE_CHARACTER;
|
||||
}
|
||||
defaultEscapeCharacter = escapeCharacter;
|
||||
}
|
||||
return escapeCharacter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
120
spring-core/src/test/java/org/springframework/core/env/AbstractPropertyResolverTests.java
vendored
Normal file
120
spring-core/src/test/java/org/springframework/core/env/AbstractPropertyResolverTests.java
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.env;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.SpringProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.springframework.core.env.AbstractPropertyResolver.DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME;
|
||||
import static org.springframework.core.env.AbstractPropertyResolver.UNDEFINED_ESCAPE_CHARACTER;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AbstractPropertyResolver}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.7
|
||||
*/
|
||||
class AbstractPropertyResolverTests {
|
||||
|
||||
@BeforeEach
|
||||
void resetStateBeforeEachTest() {
|
||||
resetState();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void resetState() {
|
||||
AbstractPropertyResolver.defaultEscapeCharacter = UNDEFINED_ESCAPE_CHARACTER;
|
||||
setSpringProperty(null);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterWithSpringPropertySetToCharacterMinValue() {
|
||||
setSpringProperty("" + Character.MIN_VALUE);
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(AbstractPropertyResolver::getDefaultEscapeCharacter)
|
||||
.withMessage("Value for property [%s] must not be Character.MIN_VALUE",
|
||||
DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME);
|
||||
|
||||
assertThat(AbstractPropertyResolver.defaultEscapeCharacter).isEqualTo(UNDEFINED_ESCAPE_CHARACTER);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterWithSpringPropertySetToXyz() {
|
||||
setSpringProperty("XYZ");
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(AbstractPropertyResolver::getDefaultEscapeCharacter)
|
||||
.withMessage("Value [XYZ] for property [%s] must be a single character or an empty string",
|
||||
DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME);
|
||||
|
||||
assertThat(AbstractPropertyResolver.defaultEscapeCharacter).isEqualTo(UNDEFINED_ESCAPE_CHARACTER);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterWithSpringPropertySetToEmptyString() {
|
||||
setSpringProperty("");
|
||||
assertEscapeCharacter(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterWithoutSpringPropertySet() {
|
||||
assertEscapeCharacter('\\');
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterWithSpringPropertySetToBackslash() {
|
||||
setSpringProperty("\\");
|
||||
assertEscapeCharacter('\\');
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterWithSpringPropertySetToTilde() {
|
||||
setSpringProperty("~");
|
||||
assertEscapeCharacter('~');
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDefaultEscapeCharacterFromMultipleThreads() {
|
||||
setSpringProperty("~");
|
||||
|
||||
IntStream.range(1, 32).parallel().forEach(__ ->
|
||||
assertThat(AbstractPropertyResolver.getDefaultEscapeCharacter()).isEqualTo('~'));
|
||||
|
||||
assertThat(AbstractPropertyResolver.defaultEscapeCharacter).isEqualTo('~');
|
||||
}
|
||||
|
||||
|
||||
private static void setSpringProperty(String value) {
|
||||
SpringProperties.setProperty(DEFAULT_PLACEHOLDER_ESCAPE_CHARACTER_PROPERTY_NAME, value);
|
||||
}
|
||||
|
||||
private static void assertEscapeCharacter(@Nullable Character expected) {
|
||||
assertThat(AbstractPropertyResolver.getDefaultEscapeCharacter()).isEqualTo(expected);
|
||||
assertThat(AbstractPropertyResolver.defaultEscapeCharacter).isEqualTo(expected);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user