diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java index 1468e030271b..a01c9be06578 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java @@ -34,7 +34,6 @@ import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.PlaceholdersResolver; -import org.springframework.boot.context.properties.source.ConfigurationPropertyName; import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.core.env.ConfigurableEnvironment; @@ -98,9 +97,6 @@ class ConfigDataEnvironment { private static final ConfigDataLocation[] EMPTY_LOCATIONS = new ConfigDataLocation[0]; - private static final ConfigurationPropertyName INCLUDE_PROFILES = ConfigurationPropertyName - .of(Profiles.INCLUDE_PROFILES_PROPERTY_NAME); - private static final Bindable CONFIG_DATA_LOCATION_ARRAY = Bindable .of(ConfigDataLocation[].class); @@ -293,9 +289,9 @@ private Collection getIncludedProfiles(ConfigDataEnvironmentCo continue; } Binder binder = new Binder(Collections.singleton(source), placeholdersResolver); - binder.bind(INCLUDE_PROFILES, STRING_LIST).ifBound((includes) -> { + binder.bind(Profiles.INCLUDE_PROFILES, STRING_LIST).ifBound((includes) -> { if (!contributor.isActive(activationContext)) { - InactiveConfigDataAccessException.throwIfPropertyFound(contributor, INCLUDE_PROFILES); + InactiveConfigDataAccessException.throwIfPropertyFound(contributor, Profiles.INCLUDE_PROFILES); } result.addAll(includes); }); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java index fdcca1d897fe..d4f6bd463784 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -55,6 +55,8 @@ class ConfigDataEnvironmentContributor implements Iterable propertySource; private final ConfigurationPropertySource configurationPropertySource; @@ -72,6 +74,7 @@ class ConfigDataEnvironmentContributor implements Iterable propertySource, ConfigurationPropertySource configurationPropertySource, - ConfigDataProperties properties, boolean ignoreImports, - Map> children) { + boolean profileSpecific, PropertySource propertySource, + ConfigurationPropertySource configurationPropertySource, ConfigDataProperties properties, + boolean ignoreImports, Map> children) { this.kind = kind; this.location = location; this.resource = resource; + this.profileSpecific = profileSpecific; this.properties = properties; this.propertySource = propertySource; this.configurationPropertySource = configurationPropertySource; @@ -122,6 +126,14 @@ ConfigDataResource getResource() { return this.resource; } + /** + * Return if the contributor is from a profile specific import. + * @return if the contributor is profile specific + */ + boolean isProfileSpecific() { + return this.profileSpecific; + } + /** * Return the property source for this contributor. * @return the property source or {@code null} @@ -201,7 +213,8 @@ ConfigDataEnvironmentContributor withBoundProperties(Binder binder) { properties = properties.withoutImports(); } return new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, this.location, this.resource, - this.propertySource, this.configurationPropertySource, properties, this.ignoreImports, null); + this.profileSpecific, this.propertySource, this.configurationPropertySource, properties, + this.ignoreImports, null); } /** @@ -215,8 +228,9 @@ ConfigDataEnvironmentContributor withChildren(ImportPhase importPhase, List children) { Map> updatedChildren = new LinkedHashMap<>(this.children); updatedChildren.put(importPhase, children); - return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource, this.propertySource, - this.configurationPropertySource, this.properties, this.ignoreImports, updatedChildren); + return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource, this.profileSpecific, + this.propertySource, this.configurationPropertySource, this.properties, this.ignoreImports, + updatedChildren); } /** @@ -240,8 +254,9 @@ ConfigDataEnvironmentContributor withReplacement(ConfigDataEnvironmentContributo } updatedChildren.put(importPhase, Collections.unmodifiableList(updatedContributors)); }); - return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource, this.propertySource, - this.configurationPropertySource, this.properties, this.ignoreImports, updatedChildren); + return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource, this.profileSpecific, + this.propertySource, this.configurationPropertySource, this.properties, this.ignoreImports, + updatedChildren); } /** @@ -252,7 +267,7 @@ ConfigDataEnvironmentContributor withReplacement(ConfigDataEnvironmentContributo static ConfigDataEnvironmentContributor of(List contributors) { Map> children = new LinkedHashMap<>(); children.put(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.unmodifiableList(contributors)); - return new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, null, null, null, false, children); + return new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, false, null, null, null, false, children); } /** @@ -265,8 +280,8 @@ static ConfigDataEnvironmentContributor of(List imports = Collections.singletonList(initialImport); ConfigDataProperties properties = new ConfigDataProperties(imports, null); - return new ConfigDataEnvironmentContributor(Kind.INITIAL_IMPORT, null, null, null, null, properties, false, - null); + return new ConfigDataEnvironmentContributor(Kind.INITIAL_IMPORT, null, null, false, null, null, properties, + false, null); } /** @@ -277,7 +292,7 @@ static ConfigDataEnvironmentContributor ofInitialImport(ConfigDataLocation initi * @return a new {@link ConfigDataEnvironmentContributor} instance */ static ConfigDataEnvironmentContributor ofExisting(PropertySource propertySource) { - return new ConfigDataEnvironmentContributor(Kind.EXISTING, null, null, propertySource, + return new ConfigDataEnvironmentContributor(Kind.EXISTING, null, null, false, propertySource, ConfigurationPropertySource.from(propertySource), null, false, null); } @@ -287,26 +302,29 @@ static ConfigDataEnvironmentContributor ofExisting(PropertySource propertySou * import further contributors later. * @param location the location of this contributor * @param resource the config data resource + * @param profileSpecific if the contributor is from a profile specific import * @param configData the config data * @param propertySourceIndex the index of the property source that should be used * @return a new {@link ConfigDataEnvironmentContributor} instance */ static ConfigDataEnvironmentContributor ofUnboundImport(ConfigDataLocation location, ConfigDataResource resource, - ConfigData configData, int propertySourceIndex) { + boolean profileSpecific, ConfigData configData, int propertySourceIndex) { PropertySource propertySource = configData.getPropertySources().get(propertySourceIndex); ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(propertySource); boolean ignoreImports = configData.getOptions().contains(ConfigData.Option.IGNORE_IMPORTS); - return new ConfigDataEnvironmentContributor(Kind.UNBOUND_IMPORT, location, resource, propertySource, - configurationPropertySource, null, ignoreImports, null); + return new ConfigDataEnvironmentContributor(Kind.UNBOUND_IMPORT, location, resource, profileSpecific, + propertySource, configurationPropertySource, null, ignoreImports, null); } /** * Factory method to create an {@link Kind#EMPTY_LOCATION empty location} contributor. * @param location the location of this contributor + * @param profileSpecific if the contributor is from a profile specific import * @return a new {@link ConfigDataEnvironmentContributor} instance */ - static ConfigDataEnvironmentContributor ofEmptyLocation(ConfigDataLocation location) { - return new ConfigDataEnvironmentContributor(Kind.EMPTY_LOCATION, location, null, null, null, null, true, null); + static ConfigDataEnvironmentContributor ofEmptyLocation(ConfigDataLocation location, boolean profileSpecific) { + return new ConfigDataEnvironmentContributor(Kind.EMPTY_LOCATION, location, null, profileSpecific, null, null, + null, true, null); } /** diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java index 2bd6c4c4ddf5..a3c345d70fed 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -163,12 +163,14 @@ private List asContributors( imported.forEach((resolutionResult, data) -> { ConfigDataLocation location = resolutionResult.getLocation(); ConfigDataResource resource = resolutionResult.getResource(); + boolean profileSpecific = resolutionResult.isProfileSpecific(); if (data.getPropertySources().isEmpty()) { - contributors.add(ConfigDataEnvironmentContributor.ofEmptyLocation(location)); + contributors.add(ConfigDataEnvironmentContributor.ofEmptyLocation(location, profileSpecific)); } else { for (int i = data.getPropertySources().size() - 1; i >= 0; i--) { - contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource, data, i)); + contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource, + profileSpecific, data, i)); } } }); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java index ab77cb3adbac..3951c07c7560 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -111,21 +111,21 @@ List resolve(ConfigDataLocationResolverContext conte private List resolve(ConfigDataLocationResolver resolver, ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles) { - List resolved = resolve(location, () -> resolver.resolve(context, location)); + List resolved = resolve(location, false, () -> resolver.resolve(context, location)); if (profiles == null) { return resolved; } - List profileSpecific = resolve(location, + List profileSpecific = resolve(location, true, () -> resolver.resolveProfileSpecific(context, location, profiles)); return merge(resolved, profileSpecific); } - private List resolve(ConfigDataLocation location, + private List resolve(ConfigDataLocation location, boolean profileSpecific, Supplier> resolveAction) { List resources = nonNullList(resolveAction.get()); List resolved = new ArrayList<>(resources.size()); for (ConfigDataResource resource : resources) { - resolved.add(new ConfigDataResolutionResult(location, resource)); + resolved.add(new ConfigDataResolutionResult(location, resource, profileSpecific)); } return resolved; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataProperties.java index 6ece35855182..37be6a312151 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -94,7 +94,7 @@ ConfigDataProperties withoutImports() { ConfigDataProperties withLegacyProfiles(String[] legacyProfiles, ConfigurationProperty property) { if (this.activate != null && !ObjectUtils.isEmpty(this.activate.onProfile)) { - throw new InvalidConfigDataPropertyException(property, NAME.append("activate.on-profile"), null); + throw new InvalidConfigDataPropertyException(property, false, NAME.append("activate.on-profile"), null); } return new ConfigDataProperties(this.imports, new Activate(this.activate.onCloudPlatform, legacyProfiles)); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResolutionResult.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResolutionResult.java index 09c7d7aed3f5..d7c35255f4ec 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResolutionResult.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResolutionResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -28,9 +28,12 @@ class ConfigDataResolutionResult { private final ConfigDataResource resource; - ConfigDataResolutionResult(ConfigDataLocation location, ConfigDataResource resource) { + private final boolean profileSpecific; + + ConfigDataResolutionResult(ConfigDataLocation location, ConfigDataResource resource, boolean profileSpecific) { this.location = location; this.resource = resource; + this.profileSpecific = profileSpecific; } ConfigDataLocation getLocation() { @@ -41,4 +44,8 @@ ConfigDataResource getResource() { return this.resource; } + boolean isProfileSpecific() { + return this.profileSpecific; + } + } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/InvalidConfigDataPropertyException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/InvalidConfigDataPropertyException.java index fc77435d70f1..cc85e435f315 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/InvalidConfigDataPropertyException.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/InvalidConfigDataPropertyException.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -18,13 +18,16 @@ import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.springframework.boot.context.properties.source.ConfigurationProperty; import org.springframework.boot.context.properties.source.ConfigurationPropertyName; import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.core.env.AbstractEnvironment; /** * Exception thrown if an invalid property is found when processing config data. @@ -35,12 +38,23 @@ */ public class InvalidConfigDataPropertyException extends ConfigDataException { - private static final Map WARNING; + private static final Map WARNINGS; static { - Map warning = new LinkedHashMap<>(); - warning.put(ConfigurationPropertyName.of("spring.profiles"), + Map warnings = new LinkedHashMap<>(); + warnings.put(ConfigurationPropertyName.of("spring.profiles"), ConfigurationPropertyName.of("spring.config.activate.on-profile")); - WARNING = Collections.unmodifiableMap(warning); + WARNINGS = Collections.unmodifiableMap(warnings); + } + + private static final Set PROFILE_SPECIFIC_ERRORS; + static { + Set errors = new LinkedHashSet<>(); + errors.add(Profiles.INCLUDE_PROFILES); + errors.add(ConfigurationPropertyName.of(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME)); + errors.add(ConfigurationPropertyName.of(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME)); + errors.add(ConfigurationPropertyName.of("spring.config.activate.on-profile")); + errors.add(ConfigurationPropertyName.of("spring.profiles")); + PROFILE_SPECIFIC_ERRORS = Collections.unmodifiableSet(errors); } private final ConfigurationProperty property; @@ -49,9 +63,9 @@ public class InvalidConfigDataPropertyException extends ConfigDataException { private final ConfigDataResource location; - InvalidConfigDataPropertyException(ConfigurationProperty property, ConfigurationPropertyName replacement, - ConfigDataResource location) { - super(getMessage(property, replacement, location), null); + InvalidConfigDataPropertyException(ConfigurationProperty property, boolean profileSpecific, + ConfigurationPropertyName replacement, ConfigDataResource location) { + super(getMessage(property, profileSpecific, replacement, location), null); this.property = property; this.replacement = replacement; this.location = location; @@ -94,17 +108,25 @@ public ConfigurationPropertyName getReplacement() { static void throwOrWarn(Log logger, ConfigDataEnvironmentContributor contributor) { ConfigurationPropertySource propertySource = contributor.getConfigurationPropertySource(); if (propertySource != null) { - WARNING.forEach((invalid, replacement) -> { - ConfigurationProperty property = propertySource.getConfigurationProperty(invalid); + WARNINGS.forEach((name, replacement) -> { + ConfigurationProperty property = propertySource.getConfigurationProperty(name); if (property != null) { - logger.warn(getMessage(property, replacement, contributor.getResource())); + logger.warn(getMessage(property, false, replacement, contributor.getResource())); } }); + if (contributor.isProfileSpecific()) { + PROFILE_SPECIFIC_ERRORS.forEach((name) -> { + ConfigurationProperty property = propertySource.getConfigurationProperty(name); + if (property != null) { + throw new InvalidConfigDataPropertyException(property, true, null, contributor.getResource()); + } + }); + } } } - private static String getMessage(ConfigurationProperty property, ConfigurationPropertyName replacement, - ConfigDataResource location) { + private static String getMessage(ConfigurationProperty property, boolean profileSpecific, + ConfigurationPropertyName replacement, ConfigDataResource location) { StringBuilder message = new StringBuilder("Property '"); message.append(property.getName()); if (location != null) { @@ -112,6 +134,9 @@ private static String getMessage(ConfigurationProperty property, ConfigurationPr message.append(location); } message.append("' is invalid"); + if (profileSpecific) { + message.append(" in a profile specific resource"); + } if (replacement != null) { message.append(" and should be replaced with '"); message.append(replacement); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java index c12088ccd9e7..4f41785cdf2c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -30,6 +30,7 @@ import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; import org.springframework.core.ResolvableType; import org.springframework.core.env.AbstractEnvironment; import org.springframework.core.env.Environment; @@ -54,6 +55,9 @@ public class Profiles implements Iterable { */ public static final String INCLUDE_PROFILES_PROPERTY_NAME = "spring.profiles.include"; + static final ConfigurationPropertyName INCLUDE_PROFILES = ConfigurationPropertyName + .of(Profiles.INCLUDE_PROFILES_PROPERTY_NAME); + private static final Bindable> STRING_STRINGS_MAP = Bindable .of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class)); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java index 3ee14d5f7fa6..47e96695fbaa 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -122,7 +122,7 @@ static class TestConfigDataEnvironmentContributor extends ConfigDataEnvironmentC private final boolean active; protected TestConfigDataEnvironmentContributor(PropertySource propertySource, boolean active) { - super(Kind.ROOT, null, null, propertySource, null, null, false, null); + super(Kind.ROOT, null, null, false, propertySource, null, null, false, null); this.active = active; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java index 4dc99e18ec0f..42fe1b5968db 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -84,7 +84,7 @@ void getLocationReturnsLocation() { ConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigDataResource resource = mock(ConfigDataResource.class); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION, - resource, configData, 0); + resource, false, configData, 0); assertThat(contributor.getResource()).isSameAs(resource); } @@ -101,7 +101,7 @@ void getConfigurationPropertySourceReturnsAdaptedPropertySource() { propertySource.setProperty("spring", "boot"); ConfigData configData = new ConfigData(Collections.singleton(propertySource)); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null, - configData, 0); + false, configData, 0); assertThat(contributor.getConfigurationPropertySource() .getConfigurationProperty(ConfigurationPropertyName.of("spring")).getValue()).isEqualTo("boot"); } @@ -284,7 +284,7 @@ void ofUnboundImportCreatesImportedContributor() { propertySource.setProperty("spring.config.import", "test"); ConfigData configData = new ConfigData(Collections.singleton(propertySource)); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION, - resource, configData, 0); + resource, false, configData, 0); assertThat(contributor.getKind()).isEqualTo(Kind.UNBOUND_IMPORT); assertThat(contributor.getResource()).isSameAs(resource); assertThat(contributor.getImports()).isEmpty(); @@ -342,7 +342,7 @@ private ConfigDataEnvironmentContributor createBoundContributor(String location) private ConfigDataEnvironmentContributor createBoundContributor(ConfigDataResource resource, ConfigData configData, int propertySourceIndex) { ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION, - resource, configData, propertySourceIndex); + resource, false, configData, propertySourceIndex); Binder binder = new Binder(contributor.getConfigurationPropertySource()); return contributor.withBoundProperties(binder); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java index c6c430ecda06..54ca2020c003 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -117,7 +117,7 @@ void withProcessedImportsResolvesAndLoads() { List locations = Arrays.asList(LOCATION_1); MockPropertySource propertySource = new MockPropertySource(); Map imported = new LinkedHashMap<>(); - imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a")), + imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false), new ConfigData(Arrays.asList(propertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) .willReturn(imported); @@ -140,14 +140,14 @@ void withProcessedImportsResolvesAndLoadsChainedImports() { MockPropertySource initialPropertySource = new MockPropertySource(); initialPropertySource.setProperty("spring.config.import", "location2"); Map initialImported = new LinkedHashMap<>(); - initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a")), + initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false), new ConfigData(Arrays.asList(initialPropertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations))) .willReturn(initialImported); List secondLocations = Arrays.asList(LOCATION_2); MockPropertySource secondPropertySource = new MockPropertySource(); Map secondImported = new LinkedHashMap<>(); - secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b")), + secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b"), false), new ConfigData(Arrays.asList(secondPropertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations))) .willReturn(secondImported); @@ -174,7 +174,7 @@ void withProcessedImportsProvidesLocationResolverContextWithAccessToBinder() { List locations = Arrays.asList(LOCATION_1); MockPropertySource propertySource = new MockPropertySource(); Map imported = new LinkedHashMap<>(); - imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'")), + imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false), new ConfigData(Arrays.asList(propertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) .willReturn(imported); @@ -194,14 +194,14 @@ void withProcessedImportsProvidesLocationResolverContextWithAccessToParent() { MockPropertySource initialPropertySource = new MockPropertySource(); initialPropertySource.setProperty("spring.config.import", "location2"); Map initialImported = new LinkedHashMap<>(); - initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a")), + initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false), new ConfigData(Arrays.asList(initialPropertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations))) .willReturn(initialImported); List secondLocations = Arrays.asList(LOCATION_2); MockPropertySource secondPropertySource = new MockPropertySource(); Map secondImported = new LinkedHashMap<>(); - secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b")), + secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b"), false), new ConfigData(Arrays.asList(secondPropertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations))) .willReturn(secondImported); @@ -224,7 +224,7 @@ void withProcessedImportsProvidesLocationResolverContextWithAccessToBootstrapReg List locations = Arrays.asList(LOCATION_1); MockPropertySource propertySource = new MockPropertySource(); Map imported = new LinkedHashMap<>(); - imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'")), + imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false), new ConfigData(Arrays.asList(propertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) .willReturn(imported); @@ -247,7 +247,7 @@ void withProcessedImportsProvidesLoaderContextWithAccessToBootstrapRegistry() { List locations = Arrays.asList(LOCATION_1); MockPropertySource propertySource = new MockPropertySource(); Map imported = new LinkedHashMap<>(); - imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'")), + imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false), new ConfigData(Arrays.asList(propertySource))); given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations))) .willReturn(imported); @@ -386,7 +386,7 @@ void getBinderWhenFailOnBindToInactiveSourceWithResolveToInactiveThrowsException private ConfigDataEnvironmentContributor createBoundImportContributor(ConfigData configData, int propertySourceIndex) { ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null, - configData, propertySourceIndex); + false, configData, propertySourceIndex); Binder binder = new Binder(contributor.getConfigurationPropertySource()); return contributor.withBoundProperties(binder); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java index f9fab256442e..479fb556734f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java @@ -636,8 +636,8 @@ void runWhenHasIncludedProfilesWithProfileSpecificDocumentThrowsException() { @Test void runWhenHasIncludedProfilesWithProfileSpecificFileThrowsException() { - assertThatExceptionOfType(InactiveConfigDataAccessException.class).isThrownBy(() -> this.application - .run("--spring.config.name=application-include-profiles-in-profile-specific-document")); + assertThatExceptionOfType(InvalidConfigDataPropertyException.class).isThrownBy(() -> this.application + .run("--spring.config.name=application-include-profiles-in-profile-specific-file")); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java index 76df8e511f08..73082f3f6aea 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -81,9 +81,9 @@ void loadImportsResolvesAndLoadsLocations() throws Exception { ConfigData configData1 = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigData configData2 = new ConfigData(Collections.singleton(new MockPropertySource())); given(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles)) - .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1))); + .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1, false))); given(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles)) - .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2))); + .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2, false))); given(this.loaders.load(this.loaderContext, resource1)).willReturn(configData1); given(this.loaders.load(this.loaderContext, resource2)).willReturn(configData2); ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL, @@ -107,11 +107,11 @@ void loadImportsWhenAlreadyImportedLocationSkipsLoad() throws Exception { ConfigData configData2 = new ConfigData(Collections.singleton(new MockPropertySource())); ConfigData configData3 = new ConfigData(Collections.singleton(new MockPropertySource())); given(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles)) - .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1))); + .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1, false))); given(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles)) - .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2))); + .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2, false))); given(this.resolvers.resolve(this.locationResolverContext, location3, this.profiles)) - .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location3, resource3))); + .willReturn(Collections.singletonList(new ConfigDataResolutionResult(location3, resource3, false))); given(this.loaders.load(this.loaderContext, resource1)).willReturn(configData1); given(this.loaders.load(this.loaderContext, resource2)).willReturn(configData2); given(this.loaders.load(this.loaderContext, resource3)).willReturn(configData3); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/InvalidConfigDataPropertyExceptionTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/InvalidConfigDataPropertyExceptionTests.java index 69bb6fadee6e..bd94cb365f1a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/InvalidConfigDataPropertyExceptionTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/InvalidConfigDataPropertyExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -20,8 +20,10 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind; import org.springframework.boot.context.properties.source.ConfigurationProperty; import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.origin.MockOrigin; import org.springframework.mock.env.MockPropertySource; @@ -50,46 +52,54 @@ class InvalidConfigDataPropertyExceptionTests { @Test void createHasCorrectMessage() { - assertThat(new InvalidConfigDataPropertyException(this.property, this.replacement, this.resource)).hasMessage( - "Property 'invalid' imported from location 'test' is invalid and should be replaced with 'replacement' [origin: origin]"); + assertThat(new InvalidConfigDataPropertyException(this.property, false, this.replacement, this.resource)) + .hasMessage( + "Property 'invalid' imported from location 'test' is invalid and should be replaced with 'replacement' [origin: origin]"); } @Test void createWhenNoLocationHasCorrectMessage() { - assertThat(new InvalidConfigDataPropertyException(this.property, this.replacement, null)) + assertThat(new InvalidConfigDataPropertyException(this.property, false, this.replacement, null)) .hasMessage("Property 'invalid' is invalid and should be replaced with 'replacement' [origin: origin]"); } @Test void createWhenNoReplacementHasCorrectMessage() { - assertThat(new InvalidConfigDataPropertyException(this.property, null, this.resource)) + assertThat(new InvalidConfigDataPropertyException(this.property, false, null, this.resource)) .hasMessage("Property 'invalid' imported from location 'test' is invalid [origin: origin]"); } @Test void createWhenNoOriginHasCorrectMessage() { ConfigurationProperty property = new ConfigurationProperty(this.invalid, "bad", null); - assertThat(new InvalidConfigDataPropertyException(property, this.replacement, this.resource)).hasMessage( + assertThat(new InvalidConfigDataPropertyException(property, false, this.replacement, this.resource)).hasMessage( "Property 'invalid' imported from location 'test' is invalid and should be replaced with 'replacement'"); } + @Test + void createWhenProfileSpecificHasCorrectMessage() { + ConfigurationProperty property = new ConfigurationProperty(this.invalid, "bad", null); + assertThat(new InvalidConfigDataPropertyException(property, true, null, this.resource)).hasMessage( + "Property 'invalid' imported from location 'test' is invalid in a profile specific resource"); + } + @Test void getPropertyReturnsProperty() { - InvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, + InvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, false, this.replacement, this.resource); assertThat(exception.getProperty()).isEqualTo(this.property); } @Test void getLocationReturnsLocation() { - InvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, + InvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, false, this.replacement, this.resource); assertThat(exception.getLocation()).isEqualTo(this.resource); } @Test void getReplacementReturnsReplacement() { - InvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, + InvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, false, this.replacement, this.resource); assertThat(exception.getReplacement()).isEqualTo(this.replacement); } @@ -106,6 +116,25 @@ void throwOrWarnWhenHasInvalidPropertyThrowsException() { + "'spring.config.activate.on-profile'"); } + @Test + void throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException() { + throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException("spring.profiles.include"); + throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException("spring.profiles.active"); + throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException("spring.profiles.default"); + throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException("spring.config.activate.on-profile"); + throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException("spring.profiles"); + } + + private void throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException(String name) { + MockPropertySource propertySource = new MockPropertySource(); + propertySource.setProperty(name, "a"); + ConfigDataEnvironmentContributor contributor = new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, null, + null, true, propertySource, ConfigurationPropertySource.from(propertySource), null, false, null); + assertThatExceptionOfType(InvalidConfigDataPropertyException.class) + .isThrownBy(() -> InvalidConfigDataPropertyException.throwOrWarn(this.logger, contributor)) + .withMessageStartingWith("Property '" + name + "' is invalid in a profile specific resource"); + } + @Test void throwOrWarnWhenHasNoInvalidPropertyDoesNothing() { ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor