From 75e0bc9271e6d5089f6c47f81114d58d09383c7d Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 17 Feb 2015 03:09:24 +0100 Subject: [PATCH] Open up TestPropertySourceUtils for public consumption Spring Framework 4.1 introduced support for @TestPropertySource; however, the utilities used to parse inlined properties and add test property sources to the environment are currently private which prevents reuse by third-party frameworks like Spring Boot. This commit addresses this issue by making such utilities public. - TestPropertySourceUtils is now a public class. - Various utility methods in TestPropertySourceUtils have been made public. - addResourcePropertySourcesToEnvironment() has been renamed to addPropertiesFilesToEnvironment(). - extractEnvironmentProperties() has been renamed to convertInlinedPropertiesToMap(). - All public methods in TestPropertySourceUtils are now fully documented. Issue: SPR-12721 --- .../support/AbstractContextLoader.java | 4 +- .../support/TestPropertySourceUtils.java | 72 ++++++++++++++----- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java index dc608162e6..d8ae5a6611 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java @@ -119,13 +119,15 @@ public abstract class AbstractContextLoader implements SmartContextLoader { * @param context the newly created application context * @param mergedConfig the merged context configuration * @since 3.2 + * @see TestPropertySourceUtils#addPropertiesFilesToEnvironment + * @see TestPropertySourceUtils#addInlinedPropertiesToEnvironment * @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext) * @see #loadContext(MergedContextConfiguration) * @see ConfigurableApplicationContext#setId */ protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles()); - TestPropertySourceUtils.addResourcePropertySourcesToEnvironment(context, mergedConfig.getPropertySourceLocations()); + TestPropertySourceUtils.addPropertiesFilesToEnvironment(context, mergedConfig.getPropertySourceLocations()); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, mergedConfig.getPropertySourceProperties()); invokeApplicationContextInitializers(context, mergedConfig); } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java index 90b8002d24..a4790c9299 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java @@ -31,8 +31,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.core.env.PropertySources; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePropertySource; import org.springframework.test.context.TestPropertySource; @@ -54,7 +56,7 @@ import static org.springframework.test.util.MetaAnnotationUtils.*; * @since 4.1 * @see TestPropertySource */ -abstract class TestPropertySourceUtils { +public abstract class TestPropertySourceUtils { private static final Log logger = LogFactory.getLog(TestPropertySourceUtils.class); @@ -147,18 +149,27 @@ abstract class TestPropertySourceUtils { } /** + * Add the {@link Properties} files from the given resource {@code locations} + * to the {@link Environment} of the supplied {@code context}. + *

Each properties file will be converted to a {@code ResourcePropertySource} + * that will be added to the {@link PropertySources} of the environment with + * highest precedence. + * @param context the application context whose environment should be updated + * @param locations the resource locations of {@link Properties} files to add + * to the environment * @since 4.1.5 + * @see ResourcePropertySource + * @see TestPropertySource#locations + * @throws IllegalStateException if an error occurs while processing a properties file */ - static void addResourcePropertySourcesToEnvironment(ConfigurableApplicationContext context, - String[] propertySourceLocations) { + public static void addPropertiesFilesToEnvironment(ConfigurableApplicationContext context, + String[] locations) { try { ConfigurableEnvironment environment = context.getEnvironment(); - String[] locations = propertySourceLocations; for (String location : locations) { String resolvedLocation = environment.resolveRequiredPlaceholders(location); Resource resource = context.getResource(resolvedLocation); - ResourcePropertySource ps = new ResourcePropertySource(resource); - environment.getPropertySources().addFirst(ps); + environment.getPropertySources().addFirst(new ResourcePropertySource(resource)); } } catch (IOException e) { @@ -167,36 +178,61 @@ abstract class TestPropertySourceUtils { } /** + * Add the given inlined properties (in the form of key-value + * pairs) to the {@link Environment} of the supplied {@code context}. + *

This method simply delegates to + * {@link #addInlinedPropertiesToEnvironment(ConfigurableEnvironment, String[])}. + * @param context the application context whose environment should be updated + * @param inlinedProperties the inlined properties to add to the environment * @since 4.1.5 + * @see TestPropertySource#properties + * @see #addInlinedPropertiesToEnvironment(ConfigurableEnvironment, String[]) */ - static void addInlinedPropertiesToEnvironment(ConfigurableApplicationContext context, - String[] propertySourceProperties) { - addInlinedPropertiesToEnvironment(context.getEnvironment(), propertySourceProperties); + public static void addInlinedPropertiesToEnvironment(ConfigurableApplicationContext context, + String[] inlinedProperties) { + addInlinedPropertiesToEnvironment(context.getEnvironment(), inlinedProperties); } /** + * Add the given inlined properties (in the form of key-value + * pairs) to the supplied {@link ConfigurableEnvironment environment}. + *

All key-value pairs will be added to the {@code Environment} as a + * single {@link MapPropertySource} with the highest precedence. + *

For details on the parsing of inlined properties, consult the + * Javadoc for {@link #convertInlinedPropertiesToMap}. + * @param environment the environment to update + * @param inlinedProperties the inlined properties to add to the environment * @since 4.1.5 + * @see MapPropertySource + * @see TestPropertySource#properties + * @see #convertInlinedPropertiesToMap */ - static void addInlinedPropertiesToEnvironment(ConfigurableEnvironment environment, String[] propertySourceProperties) { - if (!ObjectUtils.isEmpty(propertySourceProperties)) { - String name = "test properties " + ObjectUtils.nullSafeToString(propertySourceProperties); - MapPropertySource ps = new MapPropertySource(name, extractEnvironmentProperties(propertySourceProperties)); + public static void addInlinedPropertiesToEnvironment(ConfigurableEnvironment environment, String[] inlinedProperties) { + if (!ObjectUtils.isEmpty(inlinedProperties)) { + String name = "test properties " + ObjectUtils.nullSafeToString(inlinedProperties); + MapPropertySource ps = new MapPropertySource(name, convertInlinedPropertiesToMap(inlinedProperties)); environment.getPropertySources().addFirst(ps); } } /** - * Extract environment properties from the supplied key/value pairs, - * preserving the ordering of property names in the returned map. - *

Parsing of the key/value pairs is achieved by converting all pairs + * Convert the supplied inlined properties (in the form of key-value + * pairs) into a map keyed by property name, preserving the ordering of property names + * in the returned map. + *

Parsing of the key-value pairs is achieved by converting all pairs * into virtual properties files in memory and delegating to * {@link Properties#load(java.io.Reader)} to parse each virtual file. + *

For a full discussion of inlined properties, consult the Javadoc + * for {@link TestPropertySource#properties}. + * @since 4.1.5 + * @throws IllegalStateException if a given key-value pair cannot be parsed, or if + * a given inlined property contains multiple key-value pairs */ - private static Map extractEnvironmentProperties(String[] keyValuePairs) { + public static Map convertInlinedPropertiesToMap(String[] inlinedProperties) { Map map = new LinkedHashMap(); Properties props = new Properties(); - for (String pair : keyValuePairs) { + for (String pair : inlinedProperties) { if (!StringUtils.hasText(pair)) { continue; }