From 7d247a71e4ed07dcfc9d4d0323d2f25eb0a85676 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 8 Feb 2017 14:24:22 +0000 Subject: [PATCH] Resolve placeholders against the env in active/include profiles values The changes made in 919d0c61 meant that the value of spring.profiles.active or spring.profiles.include was only processed when a single property source, the property source for the config file being read, was available. This meant that any placeholders in those values would only be resolved against properties in the configuration file rather than against the entire environment. This commit updates the binding process so that placeholder resolution is not performed during binding against a single configuration file. Once binding has completed, the bounds values are post-processed to resolve and placeholders that they may contain. The two-step process described above is used in preference to binding against the whole environment. This avoids a problem with profiles that are active or included by property sources in the environment being processed repeatedly. Closes gh-8234 --- .../bind/PropertySourcesPropertyValues.java | 17 +++++++++++++++-- .../config/ConfigFileApplicationListener.java | 12 +++++++++++- .../ConfigFileApplicationListenerTests.java | 16 ++++++++++++++++ .../resources/testactiveprofiles.properties | 1 + 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 spring-boot/src/test/resources/testactiveprofiles.properties diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java b/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java index 5a539133ce2..14cec13c5fe 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -63,8 +63,21 @@ public class PropertySourcesPropertyValues implements PropertyValues { * @param propertySources a PropertySources instance */ public PropertySourcesPropertyValues(PropertySources propertySources) { + this(propertySources, true); + } + + /** + * Create a new PropertyValues from the given PropertySources that will optionally + * resolve placeholders. + * @param propertySources a PropertySources instance + * @param resolvePlaceholders {@code true} if placeholders should be resolved, + * otherwise {@code false} + * @since 1.5.2 + */ + public PropertySourcesPropertyValues(PropertySources propertySources, + boolean resolvePlaceholders) { this(propertySources, (Collection) null, PropertyNamePatternsMatcher.ALL, - true); + resolvePlaceholders); } /** diff --git a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index caca89d19d7..14652a93de7 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -527,10 +527,20 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SpringProfiles springProfiles = new SpringProfiles(); RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles, "spring.profiles"); - dataBinder.bind(new PropertySourcesPropertyValues(propertySources)); + dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false)); + springProfiles.setActive(resolvePlaceholders(springProfiles.getActive())); + springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude())); return springProfiles; } + private List resolvePlaceholders(List values) { + List resolved = new ArrayList(); + for (String value : values) { + resolved.add(this.environment.resolvePlaceholders(value)); + } + return resolved; + } + private void maybeActivateProfiles(Set profiles) { if (this.activatedProfiles) { if (!profiles.isEmpty()) { diff --git a/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java index 7ccd17c0522..db6dd3977e8 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java @@ -24,7 +24,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Properties; import ch.qos.logback.classic.BasicConfigurator; @@ -849,6 +851,20 @@ public class ConfigFileApplicationListenerTests { .isFalse(); } + @Test + public void activeProfilesCanBeConfiguredUsingPlaceholdersResolvedAgainstTheEnvironment() + throws Exception { + Map source = new HashMap(); + source.put("activeProfile", "testPropertySource"); + org.springframework.core.env.PropertySource propertySource = new MapPropertySource( + "test", source); + this.environment.getPropertySources().addLast(propertySource); + this.initializer.setSearchNames("testactiveprofiles"); + this.initializer.postProcessEnvironment(this.environment, this.application); + assertThat(this.environment.getActiveProfiles()) + .containsExactly("testPropertySource"); + } + private Condition matchingPropertySource( final String sourceName) { return new Condition( diff --git a/spring-boot/src/test/resources/testactiveprofiles.properties b/spring-boot/src/test/resources/testactiveprofiles.properties new file mode 100644 index 00000000000..11cdae3b77e --- /dev/null +++ b/spring-boot/src/test/resources/testactiveprofiles.properties @@ -0,0 +1 @@ +spring.profiles.active=${activeProfile:propertiesfile}