Use environment conversion service when resolving placeholders

Closes gh-39944
This commit is contained in:
Moritz Halbritter 2024-03-28 09:48:55 +01:00
parent 9c68ce5900
commit 0722ac796b
9 changed files with 228 additions and 126 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -172,20 +172,23 @@ class ConfigDataEnvironment {
else {
this.logger.trace(LogMessage.format("Creating wrapped config data contributor for '%s'",
propertySource.getName()));
contributors.add(ConfigDataEnvironmentContributor.ofExisting(propertySource));
contributors.add(ConfigDataEnvironmentContributor.ofExisting(propertySource,
this.environment.getConversionService()));
}
}
contributors.addAll(getInitialImportContributors(binder));
if (defaultPropertySource != null) {
this.logger.trace("Creating wrapped config data contributor for default property source");
contributors.add(ConfigDataEnvironmentContributor.ofExisting(defaultPropertySource));
contributors.add(ConfigDataEnvironmentContributor.ofExisting(defaultPropertySource,
this.environment.getConversionService()));
}
return createContributors(contributors);
}
protected ConfigDataEnvironmentContributors createContributors(
List<ConfigDataEnvironmentContributor> contributors) {
return new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, contributors);
return new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, contributors,
this.environment.getConversionService());
}
ConfigDataEnvironmentContributors getContributors() {
@ -215,7 +218,7 @@ class ConfigDataEnvironment {
private ConfigDataEnvironmentContributor createInitialImportContributor(ConfigDataLocation location) {
this.logger.trace(LogMessage.format("Adding initial config data import from location '%s'", location));
return ConfigDataEnvironmentContributor.ofInitialImport(location);
return ConfigDataEnvironmentContributor.ofInitialImport(location, this.environment.getConversionService());
}
/**
@ -288,7 +291,7 @@ class ConfigDataEnvironment {
private Collection<? extends String> getIncludedProfiles(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext) {
PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
contributors, activationContext, null, true);
contributors, activationContext, null, true, this.environment.getConversionService());
Set<String> result = new LinkedHashSet<>();
for (ConfigDataEnvironmentContributor contributor : contributors) {
ConfigurationPropertySource source = contributor.getConfigurationPropertySource();

View File

@ -29,6 +29,7 @@ import java.util.stream.StreamSupport;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.CollectionUtils;
@ -74,6 +75,8 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
private final Kind kind;
private final ConversionService conversionService;
/**
* Create a new {@link ConfigDataEnvironmentContributor} instance.
* @param kind the contributor kind
@ -87,11 +90,13 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* @param properties the config data properties or {@code null}
* @param configDataOptions any config data options that should apply
* @param children the children of this contributor at each {@link ImportPhase}
* @param conversionService the conversion service to use
*/
ConfigDataEnvironmentContributor(Kind kind, ConfigDataLocation location, ConfigDataResource resource,
boolean fromProfileSpecificImport, PropertySource<?> propertySource,
ConfigurationPropertySource configurationPropertySource, ConfigDataProperties properties,
ConfigData.Options configDataOptions, Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children) {
ConfigData.Options configDataOptions, Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children,
ConversionService conversionService) {
this.kind = kind;
this.location = location;
this.resource = resource;
@ -101,6 +106,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
this.configurationPropertySource = configurationPropertySource;
this.configDataOptions = (configDataOptions != null) ? configDataOptions : ConfigData.Options.NONE;
this.children = (children != null) ? children : Collections.emptyMap();
this.conversionService = conversionService;
}
/**
@ -171,7 +177,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
ConfigDataEnvironmentContributor withoutConfigDataOption(ConfigData.Option option) {
return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource,
this.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, this.properties,
this.configDataOptions.without(option), this.children);
this.configDataOptions.without(option), this.children, this.conversionService);
}
/**
@ -235,7 +241,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
ConfigDataActivationContext activationContext) {
Iterable<ConfigurationPropertySource> sources = Collections.singleton(getConfigurationPropertySource());
PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
contributors, activationContext, this, true);
contributors, activationContext, this, true, this.conversionService);
Binder binder = new Binder(sources, placeholdersResolver, null, null, null);
ConfigDataProperties properties = ConfigDataProperties.get(binder);
if (properties != null && this.configDataOptions.contains(ConfigData.Option.IGNORE_IMPORTS)) {
@ -243,7 +249,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
}
return new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, this.location, this.resource,
this.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, properties,
this.configDataOptions, null);
this.configDataOptions, null, this.conversionService);
}
/**
@ -262,7 +268,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
}
return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource,
this.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, this.properties,
this.configDataOptions, updatedChildren);
this.configDataOptions, updatedChildren, this.conversionService);
}
private void moveProfileSpecific(Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children) {
@ -337,7 +343,7 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
});
return new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource,
this.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, this.properties,
this.configDataOptions, updatedChildren);
this.configDataOptions, updatedChildren, this.conversionService);
}
@Override
@ -370,12 +376,15 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
/**
* Factory method to create a {@link Kind#ROOT root} contributor.
* @param contributors the immediate children of the root
* @param conversionService the conversion service to use
* @return a new {@link ConfigDataEnvironmentContributor} instance
*/
static ConfigDataEnvironmentContributor of(List<ConfigDataEnvironmentContributor> contributors) {
static ConfigDataEnvironmentContributor of(List<ConfigDataEnvironmentContributor> contributors,
ConversionService conversionService) {
Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children = new LinkedHashMap<>();
children.put(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.unmodifiableList(contributors));
return new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, false, null, null, null, null, children);
return new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, false, null, null, null, null, children,
conversionService);
}
/**
@ -383,13 +392,15 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* This contributor is used to trigger initial imports of additional contributors. It
* does not contribute any properties itself.
* @param initialImport the initial import location (with placeholders resolved)
* @param conversionService the conversion service to use
* @return a new {@link ConfigDataEnvironmentContributor} instance
*/
static ConfigDataEnvironmentContributor ofInitialImport(ConfigDataLocation initialImport) {
static ConfigDataEnvironmentContributor ofInitialImport(ConfigDataLocation initialImport,
ConversionService conversionService) {
List<ConfigDataLocation> imports = Collections.singletonList(initialImport);
ConfigDataProperties properties = new ConfigDataProperties(imports, null);
return new ConfigDataEnvironmentContributor(Kind.INITIAL_IMPORT, null, null, false, null, null, properties,
null, null);
null, null, conversionService);
}
/**
@ -397,11 +408,13 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* property source. The contributor provides access to existing properties, but
* doesn't actively import any additional contributors.
* @param propertySource the property source to wrap
* @param conversionService the conversion service to use
* @return a new {@link ConfigDataEnvironmentContributor} instance
*/
static ConfigDataEnvironmentContributor ofExisting(PropertySource<?> propertySource) {
static ConfigDataEnvironmentContributor ofExisting(PropertySource<?> propertySource,
ConversionService conversionService) {
return new ConfigDataEnvironmentContributor(Kind.EXISTING, null, null, false, propertySource,
ConfigurationPropertySource.from(propertySource), null, null, null);
ConfigurationPropertySource.from(propertySource), null, null, null, conversionService);
}
/**
@ -413,26 +426,30 @@ class ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironment
* @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
* @param conversionService the conversion service to use
* @return a new {@link ConfigDataEnvironmentContributor} instance
*/
static ConfigDataEnvironmentContributor ofUnboundImport(ConfigDataLocation location, ConfigDataResource resource,
boolean profileSpecific, ConfigData configData, int propertySourceIndex) {
boolean profileSpecific, ConfigData configData, int propertySourceIndex,
ConversionService conversionService) {
PropertySource<?> propertySource = configData.getPropertySources().get(propertySourceIndex);
ConfigData.Options options = configData.getOptions(propertySource);
ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(propertySource);
return new ConfigDataEnvironmentContributor(Kind.UNBOUND_IMPORT, location, resource, profileSpecific,
propertySource, configurationPropertySource, null, options, null);
propertySource, configurationPropertySource, null, options, null, conversionService);
}
/**
* 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
* @param conversionService the conversion service to use
* @return a new {@link ConfigDataEnvironmentContributor} instance
*/
static ConfigDataEnvironmentContributor ofEmptyLocation(ConfigDataLocation location, boolean profileSpecific) {
static ConfigDataEnvironmentContributor ofEmptyLocation(ConfigDataLocation location, boolean profileSpecific,
ConversionService conversionService) {
return new ConfigDataEnvironmentContributor(Kind.EMPTY_LOCATION, location, null, profileSpecific, null, null,
null, EMPTY_LOCATION_OPTIONS, null);
null, EMPTY_LOCATION_OPTIONS, null, conversionService);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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,6 +20,7 @@ import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.
import org.springframework.boot.context.properties.bind.PlaceholdersResolver;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.PropertySource;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.SystemPropertyUtils;
@ -30,6 +31,7 @@ import org.springframework.util.SystemPropertyUtils;
*
* @author Phillip Webb
* @author Madhura Bhave
* @author Moritz Halbritter
*/
class ConfigDataEnvironmentContributorPlaceholdersResolver implements PlaceholdersResolver {
@ -43,13 +45,16 @@ class ConfigDataEnvironmentContributorPlaceholdersResolver implements Placeholde
private final ConfigDataEnvironmentContributor activeContributor;
private final ConversionService conversionService;
ConfigDataEnvironmentContributorPlaceholdersResolver(Iterable<ConfigDataEnvironmentContributor> contributors,
ConfigDataActivationContext activationContext, ConfigDataEnvironmentContributor activeContributor,
boolean failOnResolveFromInactiveContributor) {
boolean failOnResolveFromInactiveContributor, ConversionService conversionService) {
this.contributors = contributors;
this.activationContext = activationContext;
this.activeContributor = activeContributor;
this.failOnResolveFromInactiveContributor = failOnResolveFromInactiveContributor;
this.conversionService = conversionService;
this.helper = new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR, true);
}
@ -77,7 +82,7 @@ class ConfigDataEnvironmentContributorPlaceholdersResolver implements Placeholde
}
result = (result != null) ? result : value;
}
return (result != null) ? String.valueOf(result) : null;
return (result != null) ? convertValueIfNecessary(result) : null;
}
private boolean isActive(ConfigDataEnvironmentContributor contributor) {
@ -91,4 +96,11 @@ class ConfigDataEnvironmentContributorPlaceholdersResolver implements Placeholde
.isActive(this.activationContext);
}
private String convertValueIfNecessary(Object value) {
if (value instanceof String string) {
return string;
}
return this.conversionService.convert(value, String.class);
}
}

View File

@ -39,6 +39,7 @@ 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.convert.ConversionService;
import org.springframework.core.log.LogMessage;
import org.springframework.util.ObjectUtils;
@ -59,24 +60,29 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
private final ConfigurableBootstrapContext bootstrapContext;
private final ConversionService conversionService;
/**
* Create a new {@link ConfigDataEnvironmentContributors} instance.
* @param logFactory the log factory
* @param bootstrapContext the bootstrap context
* @param contributors the initial set of contributors
* @param conversionService the conversion service to use
*/
ConfigDataEnvironmentContributors(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
List<ConfigDataEnvironmentContributor> contributors) {
List<ConfigDataEnvironmentContributor> contributors, ConversionService conversionService) {
this.logger = logFactory.getLog(getClass());
this.bootstrapContext = bootstrapContext;
this.root = ConfigDataEnvironmentContributor.of(contributors);
this.root = ConfigDataEnvironmentContributor.of(contributors, conversionService);
this.conversionService = conversionService;
}
private ConfigDataEnvironmentContributors(Log logger, ConfigurableBootstrapContext bootstrapContext,
ConfigDataEnvironmentContributor root) {
ConfigDataEnvironmentContributor root, ConversionService conversionService) {
this.logger = logger;
this.bootstrapContext = bootstrapContext;
this.root = root;
this.conversionService = conversionService;
}
/**
@ -104,7 +110,7 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
if (contributor.getKind() == Kind.UNBOUND_IMPORT) {
ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(result, activationContext);
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
result.getRoot().withReplacement(contributor, bound));
result.getRoot().withReplacement(contributor, bound), this.conversionService);
continue;
}
ConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(
@ -118,7 +124,7 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase,
asContributors(imported));
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
result.getRoot().withReplacement(contributor, contributorAndChildren));
result.getRoot().withReplacement(contributor, contributorAndChildren), this.conversionService);
processed++;
}
}
@ -161,12 +167,13 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
ConfigDataResource resource = resolutionResult.getResource();
boolean profileSpecific = resolutionResult.isProfileSpecific();
if (data.getPropertySources().isEmpty()) {
contributors.add(ConfigDataEnvironmentContributor.ofEmptyLocation(location, profileSpecific));
contributors.add(ConfigDataEnvironmentContributor.ofEmptyLocation(location, profileSpecific,
this.conversionService));
}
else {
for (int i = data.getPropertySources().size() - 1; i >= 0; i--) {
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource,
profileSpecific, data, i));
profileSpecific, data, i, this.conversionService));
}
}
});
@ -214,7 +221,7 @@ class ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmen
Iterable<ConfigurationPropertySource> sources = () -> getBinderSources(
filter.and((contributor) -> failOnInactiveSource || contributor.isActive(activationContext)));
PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(this.root,
activationContext, null, failOnInactiveSource);
activationContext, null, failOnInactiveSource, this.conversionService);
BindHandler bindHandler = !failOnInactiveSource ? null : new InactiveSourceChecker(activationContext);
return new Binder(sources, placeholdersResolver, null, null, bindHandler);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -27,6 +27,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.origin.PropertySourceOrigin;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@ -38,42 +41,63 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*
* @author Phillip Webb
* @author Madhura Bhave
* @author Moritz Halbritter
*/
class ConfigDataEnvironmentContributorPlaceholdersResolverTests {
private final ConversionService conversionService = DefaultConversionService.getSharedInstance();
@Test
void resolvePlaceholdersWhenNotStringReturnsResolved() {
ConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
Collections.emptyList(), null, null, false);
Collections.emptyList(), null, null, false, this.conversionService);
assertThat(resolver.resolvePlaceholders(123)).isEqualTo(123);
}
@Test
void resolvePlaceholdersWhenNotFoundReturnsOriginal() {
ConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
Collections.emptyList(), null, null, false);
Collections.emptyList(), null, null, false, this.conversionService);
assertThat(resolver.resolvePlaceholders("${test}")).isEqualTo("${test}");
}
@Test
void resolvePlaceholdersWhenFoundReturnsFirstMatch() {
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s1", "nope", "t1"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s2", "test", "t2"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s3", "test", "t3"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s1", "nope", "t1"), true,
this.conversionService));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s2", "test", "t2"), true,
this.conversionService));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s3", "test", "t3"), true,
this.conversionService));
ConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
contributors, null, null, true);
contributors, null, null, true, this.conversionService);
assertThat(resolver.resolvePlaceholders("${test}")).isEqualTo("t2");
}
@Test
void shouldUseConversionService() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(CustomValue.class, String.class, (input) -> "custom-value");
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();
contributors.add(new TestConfigDataEnvironmentContributor(
new TestPropertySource("s1", Map.of("test", new CustomValue())), true, conversionService));
ConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
contributors, null, null, true, conversionService);
assertThat(resolver.resolvePlaceholders("${test}")).isEqualTo("custom-value");
}
@Test
void resolvePlaceholdersWhenFoundInInactiveThrowsException() {
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s1", "nope", "t1"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s2", "test", "t2"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s3", "test", "t3"), false));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s1", "nope", "t1"), true,
this.conversionService));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s2", "test", "t2"), true,
this.conversionService));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s3", "test", "t3"), false,
this.conversionService));
ConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
contributors, null, null, true);
contributors, null, null, true, this.conversionService);
assertThatExceptionOfType(InactiveConfigDataAccessException.class)
.isThrownBy(() -> resolver.resolvePlaceholders("${test}"))
.satisfies(propertyNameAndOriginOf("test", "s3"));
@ -82,11 +106,14 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests {
@Test
void resolvePlaceholderWhenFoundInInactiveAndIgnoringReturnsResolved() {
List<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s1", "nope", "t1"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s2", "test", "t2"), true));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s3", "test", "t3"), false));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s1", "nope", "t1"), true,
this.conversionService));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s2", "test", "t2"), true,
this.conversionService));
contributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource("s3", "test", "t3"), false,
this.conversionService));
ConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
contributors, null, null, false);
contributors, null, null, false, this.conversionService);
assertThat(resolver.resolvePlaceholders("${test}")).isEqualTo("t2");
}
@ -121,8 +148,9 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests {
private final boolean active;
protected TestConfigDataEnvironmentContributor(PropertySource<?> propertySource, boolean active) {
super(Kind.ROOT, null, null, false, propertySource, null, null, null, null);
protected TestConfigDataEnvironmentContributor(PropertySource<?> propertySource, boolean active,
ConversionService conversionService) {
super(Kind.ROOT, null, null, false, propertySource, null, null, null, null, conversionService);
this.active = active;
}
@ -133,4 +161,8 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests {
}
private static final class CustomValue {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -31,6 +31,8 @@ import org.springframework.boot.context.config.ConfigData.PropertySourceOptions;
import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.ImportPhase;
import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.mock.env.MockPropertySource;
import static org.assertj.core.api.Assertions.assertThat;
@ -50,15 +52,19 @@ class ConfigDataEnvironmentContributorTests {
private final ConfigDataActivationContext activationContext = new ConfigDataActivationContext(
CloudPlatform.KUBERNETES, null);
private final ConversionService conversionService = DefaultConversionService.getSharedInstance();
@Test
void getKindReturnsKind() {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(TEST_LOCATION);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(TEST_LOCATION,
this.conversionService);
assertThat(contributor.getKind()).isEqualTo(Kind.INITIAL_IMPORT);
}
@Test
void isActiveWhenPropertiesIsNullReturnsTrue() {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(TEST_LOCATION);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(TEST_LOCATION,
this.conversionService);
assertThat(contributor.isActive(null)).isTrue();
}
@ -85,14 +91,15 @@ class ConfigDataEnvironmentContributorTests {
ConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()));
ConfigDataResource resource = mock(ConfigDataResource.class);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
resource, false, configData, 0);
resource, false, configData, 0, this.conversionService);
assertThat(contributor.getResource()).isSameAs(resource);
}
@Test
void getPropertySourceReturnsPropertySource() {
MockPropertySource propertySource = new MockPropertySource();
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,
this.conversionService);
assertThat(contributor.getPropertySource()).isSameAs(propertySource);
}
@ -102,7 +109,7 @@ class ConfigDataEnvironmentContributorTests {
propertySource.setProperty("spring", "boot");
ConfigData configData = new ConfigData(Collections.singleton(propertySource));
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null,
false, configData, 0);
false, configData, 0, this.conversionService);
assertThat(contributor.getConfigurationPropertySource()
.getConfigurationProperty(ConfigurationPropertyName.of("spring"))
.getValue()).isEqualTo("boot");
@ -267,7 +274,8 @@ class ConfigDataEnvironmentContributorTests {
void ofCreatesRootContributor() {
ConfigDataEnvironmentContributor one = createBoundContributor("one");
ConfigDataEnvironmentContributor two = createBoundContributor("two");
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.of(Arrays.asList(one, two));
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.of(Arrays.asList(one, two),
this.conversionService);
assertThat(contributor.getKind()).isEqualTo(Kind.ROOT);
assertThat(contributor.getResource()).isNull();
assertThat(contributor.getImports()).isEmpty();
@ -279,7 +287,8 @@ class ConfigDataEnvironmentContributorTests {
@Test
void ofInitialImportCreatedInitialImportContributor() {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(TEST_LOCATION);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(TEST_LOCATION,
this.conversionService);
assertThat(contributor.getKind()).isEqualTo(Kind.INITIAL_IMPORT);
assertThat(contributor.getResource()).isNull();
assertThat(contributor.getImports()).containsExactly(TEST_LOCATION);
@ -294,7 +303,8 @@ class ConfigDataEnvironmentContributorTests {
MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring.config.import", "test");
propertySource.setProperty("spring.config.activate.on-cloud-platform", "cloudfoundry");
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,
this.conversionService);
assertThat(contributor.getKind()).isEqualTo(Kind.EXISTING);
assertThat(contributor.getResource()).isNull();
assertThat(contributor.getImports()).isEmpty(); // Properties must not be bound
@ -311,7 +321,7 @@ class ConfigDataEnvironmentContributorTests {
propertySource.setProperty("spring.config.import", "test");
ConfigData configData = new ConfigData(Collections.singleton(propertySource));
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
resource, false, configData, 0);
resource, false, configData, 0, this.conversionService);
assertThat(contributor.getKind()).isEqualTo(Kind.UNBOUND_IMPORT);
assertThat(contributor.getResource()).isSameAs(resource);
assertThat(contributor.getImports()).isEmpty();
@ -358,7 +368,7 @@ class ConfigDataEnvironmentContributorTests {
TestResource resource = new TestResource("a");
ConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()), Option.IGNORE_IMPORTS);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
resource, false, configData, 0);
resource, false, configData, 0, this.conversionService);
ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(Collections.singleton(contributor),
null);
assertThat(bound).isNotNull();
@ -372,7 +382,7 @@ class ConfigDataEnvironmentContributorTests {
private ConfigDataEnvironmentContributor createBoundContributor(ConfigDataResource resource, ConfigData configData,
int propertySourceIndex) {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,
resource, false, configData, propertySourceIndex);
resource, false, configData, propertySourceIndex, this.conversionService);
return contributor.withBoundProperties(Collections.singleton(contributor), null);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -37,6 +37,8 @@ import org.springframework.boot.context.config.ConfigDataEnvironmentContributors
import org.springframework.boot.context.properties.bind.BindException;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.mock.env.MockEnvironment;
@ -68,9 +70,7 @@ class ConfigDataEnvironmentContributorsTests {
private final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
private MockEnvironment environment;
private Binder binder;
private final ConversionService conversionService = DefaultConversionService.getSharedInstance();
private ConfigDataImporter importer;
@ -78,10 +78,10 @@ class ConfigDataEnvironmentContributorsTests {
@BeforeEach
void setup() {
this.environment = new MockEnvironment();
this.binder = Binder.get(this.environment);
MockEnvironment environment = new MockEnvironment();
Binder binder = Binder.get(environment);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, new DefaultResourceLoader(getClass().getClassLoader()),
binder, new DefaultResourceLoader(getClass().getClassLoader()),
SpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader()));
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
SpringFactoriesLoader.forDefaultResourceLocation());
@ -91,9 +91,10 @@ class ConfigDataEnvironmentContributorsTests {
@Test
void createCreatesWithInitialContributors() {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
Iterator<ConfigDataEnvironmentContributor> iterator = contributors.iterator();
assertThat(iterator.next()).isSameAs(contributor);
assertThat(iterator.next().getKind()).isEqualTo(Kind.ROOT);
@ -102,9 +103,9 @@ class ConfigDataEnvironmentContributorsTests {
@Test
void withProcessedImportsWhenHasNoUnprocessedImportsReturnsSameInstance() {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor
.ofExisting(new MockPropertySource());
.ofExisting(new MockPropertySource(), this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
ConfigDataEnvironmentContributors withProcessedImports = contributors.withProcessedImports(this.importer,
this.activationContext);
assertThat(withProcessedImports).isSameAs(contributors);
@ -113,16 +114,17 @@ class ConfigDataEnvironmentContributorsTests {
@Test
void withProcessedImportsResolvesAndLoads() {
this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
List<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false),
new ConfigData(Arrays.asList(propertySource)));
new ConfigData(List.of(propertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))
.willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
ConfigDataEnvironmentContributors withProcessedImports = contributors.withProcessedImports(this.importer,
this.activationContext);
Iterator<ConfigDataEnvironmentContributor> iterator = withProcessedImports.iterator();
@ -135,24 +137,25 @@ class ConfigDataEnvironmentContributorsTests {
@Test
void withProcessedImportsResolvesAndLoadsChainedImports() {
this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> initialLocations = Arrays.asList(LOCATION_1);
List<ConfigDataLocation> initialLocations = Collections.singletonList(LOCATION_1);
MockPropertySource initialPropertySource = new MockPropertySource();
initialPropertySource.setProperty("spring.config.import", "location2");
Map<ConfigDataResolutionResult, ConfigData> initialImported = new LinkedHashMap<>();
initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false),
new ConfigData(Arrays.asList(initialPropertySource)));
new ConfigData(List.of(initialPropertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations)))
.willReturn(initialImported);
List<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2);
List<ConfigDataLocation> secondLocations = Collections.singletonList(LOCATION_2);
MockPropertySource secondPropertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> secondImported = new LinkedHashMap<>();
secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b"), false),
new ConfigData(Arrays.asList(secondPropertySource)));
new ConfigData(List.of(secondPropertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations)))
.willReturn(secondImported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
ConfigDataEnvironmentContributors withProcessedImports = contributors.withProcessedImports(this.importer,
this.activationContext);
Iterator<ConfigDataEnvironmentContributor> iterator = withProcessedImports.iterator();
@ -168,18 +171,19 @@ class ConfigDataEnvironmentContributorsTests {
MockPropertySource existingPropertySource = new MockPropertySource();
existingPropertySource.setProperty("test", "springboot");
ConfigDataEnvironmentContributor existingContributor = ConfigDataEnvironmentContributor
.ofExisting(existingPropertySource);
.ofExisting(existingPropertySource, this.conversionService);
this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
List<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false),
new ConfigData(Arrays.asList(propertySource)));
new ConfigData(List.of(propertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))
.willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(existingContributor, contributor));
this.bootstrapContext, Arrays.asList(existingContributor, contributor), this.conversionService);
contributors.withProcessedImports(this.importer, this.activationContext);
then(this.importer).should()
.resolveAndLoad(any(),
@ -191,24 +195,25 @@ class ConfigDataEnvironmentContributorsTests {
@Test
void withProcessedImportsProvidesLocationResolverContextWithAccessToParent() {
this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> initialLocations = Arrays.asList(LOCATION_1);
List<ConfigDataLocation> initialLocations = Collections.singletonList(LOCATION_1);
MockPropertySource initialPropertySource = new MockPropertySource();
initialPropertySource.setProperty("spring.config.import", "location2");
Map<ConfigDataResolutionResult, ConfigData> initialImported = new LinkedHashMap<>();
initialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a"), false),
new ConfigData(Arrays.asList(initialPropertySource)));
new ConfigData(List.of(initialPropertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations)))
.willReturn(initialImported);
List<ConfigDataLocation> secondLocations = Arrays.asList(LOCATION_2);
List<ConfigDataLocation> secondLocations = Collections.singletonList(LOCATION_2);
MockPropertySource secondPropertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> secondImported = new LinkedHashMap<>();
secondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource("b"), false),
new ConfigData(Arrays.asList(secondPropertySource)));
new ConfigData(List.of(secondPropertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations)))
.willReturn(secondImported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
ArgumentCaptor<ConfigDataLocationResolverContext> locationResolverContext = ArgumentCaptor
.forClass(ConfigDataLocationResolverContext.class);
contributors.withProcessedImports(this.importer, this.activationContext);
@ -223,18 +228,19 @@ class ConfigDataEnvironmentContributorsTests {
MockPropertySource existingPropertySource = new MockPropertySource();
existingPropertySource.setProperty("test", "springboot");
ConfigDataEnvironmentContributor existingContributor = ConfigDataEnvironmentContributor
.ofExisting(existingPropertySource);
.ofExisting(existingPropertySource, this.conversionService);
this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
List<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false),
new ConfigData(Arrays.asList(propertySource)));
new ConfigData(List.of(propertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))
.willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(existingContributor, contributor));
this.bootstrapContext, Arrays.asList(existingContributor, contributor), this.conversionService);
contributors.withProcessedImports(this.importer, this.activationContext);
then(this.importer).should()
.resolveAndLoad(any(),
@ -247,18 +253,19 @@ class ConfigDataEnvironmentContributorsTests {
MockPropertySource existingPropertySource = new MockPropertySource();
existingPropertySource.setProperty("test", "springboot");
ConfigDataEnvironmentContributor existingContributor = ConfigDataEnvironmentContributor
.ofExisting(existingPropertySource);
.ofExisting(existingPropertySource, this.conversionService);
this.importer = mock(ConfigDataImporter.class);
List<ConfigDataLocation> locations = Arrays.asList(LOCATION_1);
List<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);
MockPropertySource propertySource = new MockPropertySource();
Map<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();
imported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource("a'"), false),
new ConfigData(Arrays.asList(propertySource)));
new ConfigData(List.of(propertySource)));
given(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))
.willReturn(imported);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImport(LOCATION_1,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(existingContributor, contributor));
this.bootstrapContext, Arrays.asList(existingContributor, contributor), this.conversionService);
contributors.withProcessedImports(this.importer, this.activationContext);
then(this.importer).should()
.resolveAndLoad(any(), any(),
@ -270,9 +277,10 @@ class ConfigDataEnvironmentContributorsTests {
void getBinderProvidesBinder() {
MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("test", "springboot");
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext);
assertThat(binder.bind("test", String.class).get()).isEqualTo("springboot");
}
@ -287,7 +295,7 @@ class ConfigDataEnvironmentContributorsTests {
ConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);
ConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor));
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext);
assertThat(binder.bind("test", String.class).get()).isEqualTo("one");
}
@ -303,7 +311,7 @@ class ConfigDataEnvironmentContributorsTests {
ConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);
ConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor));
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext);
assertThat(binder.bind("test", String.class).get()).isEqualTo("two");
}
@ -313,9 +321,10 @@ class ConfigDataEnvironmentContributorsTests {
MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("test", "${other}");
propertySource.setProperty("other", "springboot");
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,
this.conversionService);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(contributor));
this.bootstrapContext, List.of(contributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext);
assertThat(binder.bind("test", String.class).get()).isEqualTo("springboot");
}
@ -332,7 +341,7 @@ class ConfigDataEnvironmentContributorsTests {
ConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);
ConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor));
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext);
assertThat(binder.bind("test", String.class).get()).isEqualTo("two");
}
@ -348,7 +357,7 @@ class ConfigDataEnvironmentContributorsTests {
ConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);
ConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor));
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);
assertThatExceptionOfType(BindException.class).isThrownBy(() -> binder.bind("test", String.class))
.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(InactiveConfigDataAccessException.class));
@ -365,7 +374,7 @@ class ConfigDataEnvironmentContributorsTests {
ConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);
ConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor));
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);
assertThatExceptionOfType(BindException.class).isThrownBy(() -> binder.bind("test", String.class))
.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(InactiveConfigDataAccessException.class));
@ -383,7 +392,7 @@ class ConfigDataEnvironmentContributorsTests {
ConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);
ConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);
ConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor));
this.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService);
Binder binder = contributors.getBinder(this.activationContext, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);
assertThatExceptionOfType(BindException.class).isThrownBy(() -> binder.bind("test", String.class))
.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(InactiveConfigDataAccessException.class));
@ -392,7 +401,7 @@ class ConfigDataEnvironmentContributorsTests {
private ConfigDataEnvironmentContributor createBoundImportContributor(ConfigData configData,
int propertySourceIndex) {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null,
false, configData, propertySourceIndex);
false, configData, propertySourceIndex, this.conversionService);
return contributor.withBoundProperties(Collections.singleton(contributor), null);
}

View File

@ -42,6 +42,8 @@ import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.
import org.springframework.boot.context.config.TestConfigDataEnvironmentUpdateListener.AddedPropertySource;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@ -73,6 +75,8 @@ class ConfigDataEnvironmentTests {
private final Collection<String> additionalProfiles = Collections.emptyList();
private final ConversionService conversionService = DefaultConversionService.getSharedInstance();
@Test
void createExposesEnvironmentBinderToConfigDataLocationResolvers() {
this.environment.setProperty("spring", "boot");
@ -217,7 +221,8 @@ class ConfigDataEnvironmentTests {
ConfigData data = new ConfigData(Collections.singleton(new MapPropertySource("test", source)),
ConfigData.Option.IGNORE_PROFILES);
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of("test"),
mock(ConfigDataResource.class), false, data, 0));
mock(ConfigDataResource.class), false, data, 0,
ConfigDataEnvironmentTests.this.conversionService));
return super.createContributors(contributors);
}
@ -241,7 +246,8 @@ class ConfigDataEnvironmentTests {
source.put("spring.profiles." + property, "include");
ConfigData data = new ConfigData(Collections.singleton(new MapPropertySource("test", source)));
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of("test"),
mock(ConfigDataResource.class), false, data, 0));
mock(ConfigDataResource.class), false, data, 0,
ConfigDataEnvironmentTests.this.conversionService));
return super.createContributors(contributors);
}
@ -264,7 +270,8 @@ class ConfigDataEnvironmentTests {
source.put(property, "included");
ConfigData data = new ConfigData(Collections.singleton(new MapPropertySource("test", source)));
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of("test"),
mock(ConfigDataResource.class), false, data, 0));
mock(ConfigDataResource.class), false, data, 0,
ConfigDataEnvironmentTests.this.conversionService));
return super.createContributors(contributors);
}
@ -288,7 +295,8 @@ class ConfigDataEnvironmentTests {
ConfigData data = new ConfigData(Collections.singleton(new MapPropertySource("test", source)),
ConfigData.Option.IGNORE_PROFILES);
contributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of("test"),
mock(ConfigDataResource.class), false, data, 0));
mock(ConfigDataResource.class), false, data, 0,
ConfigDataEnvironmentTests.this.conversionService));
return super.createContributors(contributors);
}
@ -305,7 +313,7 @@ class ConfigDataEnvironmentTests {
ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,
this.environment, this.resourceLoader, this.additionalProfiles, null);
assertThatExceptionOfType(InvalidConfigDataPropertyException.class)
.isThrownBy(() -> configDataEnvironment.processAndApply());
.isThrownBy(configDataEnvironment::processAndApply);
}
@Test

View File

@ -23,6 +23,8 @@ 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.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.mock.env.MockPropertySource;
import static org.assertj.core.api.Assertions.assertThat;
@ -46,6 +48,8 @@ class InvalidConfigDataPropertyExceptionTests {
private final ConfigurationProperty property = new ConfigurationProperty(this.invalid, "bad",
MockOrigin.of("origin"));
private final ConversionService conversionService = DefaultConversionService.getSharedInstance();
@Test
void createHasCorrectMessage() {
assertThat(new InvalidConfigDataPropertyException(this.property, false, this.replacement, this.resource))
@ -104,7 +108,8 @@ class InvalidConfigDataPropertyExceptionTests {
void throwOrWarnWhenHasInvalidPropertyThrowsException() {
MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring.profiles", "a");
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource);
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,
this.conversionService);
assertThatExceptionOfType(InvalidConfigDataPropertyException.class)
.isThrownBy(() -> InvalidConfigDataPropertyException.throwIfPropertyFound(contributor))
.withMessageStartingWith("Property 'spring.profiles' is invalid and should be replaced with "
@ -136,16 +141,15 @@ class InvalidConfigDataPropertyExceptionTests {
ConfigData.Option... configDataOptions) {
MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty(name, "a");
ConfigDataEnvironmentContributor contributor = new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, null,
null, true, propertySource, ConfigurationPropertySource.from(propertySource), null,
ConfigData.Options.of(configDataOptions), null);
return contributor;
return new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, null, null, true, propertySource,
ConfigurationPropertySource.from(propertySource), null, ConfigData.Options.of(configDataOptions), null,
this.conversionService);
}
@Test
void throwOrWarnWhenHasNoInvalidPropertyDoesNothing() {
ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor
.ofExisting(new MockPropertySource());
.ofExisting(new MockPropertySource(), this.conversionService);
InvalidConfigDataPropertyException.throwIfPropertyFound(contributor);
}