Skip to content

Commit bb38ee3

Browse files
committed
Fix package tangle and polish prefix support
Polish the prefix support introduced in commit a8592f3 and fix a package tangle between `boot.context.properties.source` and `boot.env`. The `Prefix` interface has now been moved into a new default method on `OriginLookup`. See gh-3450
1 parent 2c0e0e0 commit bb38ee3

14 files changed

+192
-103
lines changed

spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc

+4-1
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ The `YamlPropertiesFactoryBean` loads YAML as `Properties` and the `YamlMapFacto
993993
You can also use the `YamlPropertySourceLoader` class if you want to load YAML as a Spring `PropertySource`.
994994

995995

996+
996997
[[boot-features-external-config-random-values]]
997998
=== Configuring Random Values
998999
The `RandomValuePropertySource` is useful for injecting random values (for example, into secrets or test cases).
@@ -1013,13 +1014,15 @@ The `+random.int*+` syntax is `OPEN value (,max) CLOSE` where the `OPEN,CLOSE` a
10131014
If `max` is provided, then `value` is the minimum value and `max` is the maximum value (exclusive).
10141015

10151016

1017+
10161018
[[boot-features-external-config-system-environment]]
10171019
=== Configuring System Environment Properties
10181020
Spring Boot supports setting a prefix for environment properties.
10191021
This is useful if the system environment is shared by multiple Spring Boot applications with different configuration requirements.
10201022
The prefix for system environment properties can be set directly on `SpringApplication`.
10211023

1022-
For example, if you set the prefix to `input`, a property such as `foo.bar` will also be resolved as `input.foo.bar` in the system environment.
1024+
For example, if you set the prefix to `input`, a property such as `remote.timeout` will also be resolved as `input.remote.timeout` in the system environment.
1025+
10231026

10241027

10251028
[[boot-features-external-config-typesafe-configuration-properties]]

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,8 @@ private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners
364364
listeners.environmentPrepared(bootstrapContext, environment);
365365
DefaultPropertiesPropertySource.moveToEnd(environment);
366366
configureAdditionalProfiles(environment);
367-
if (environment.getProperty("spring.main.environment-prefix") != null) {
368-
throw new IllegalStateException("Environment prefix cannot be set via properties.");
369-
}
367+
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
368+
"Environment prefix cannot be set via properties.");
370369
bindToSpringApplication(environment);
371370
if (!this.isCustomEnvironment) {
372371
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
@@ -1181,10 +1180,22 @@ public void setResourceLoader(ResourceLoader resourceLoader) {
11811180
this.resourceLoader = resourceLoader;
11821181
}
11831182

1183+
/**
1184+
* Return a prefix that should be applied when obtaining configuration properties from
1185+
* the system environment.
1186+
* @return the environment property prefix
1187+
* @since 2.5.0
1188+
*/
11841189
public String getEnvironmentPrefix() {
11851190
return this.environmentPrefix;
11861191
}
11871192

1193+
/**
1194+
* Set the prefix that should be applied when obtaining configuration properties from
1195+
* the system environment.
1196+
* @param environmentPrefix the environment property prefix to set
1197+
* @since 2.5.0
1198+
*/
11881199
public void setEnvironmentPrefix(String environmentPrefix) {
11891200
this.environmentPrefix = environmentPrefix;
11901201
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java

+56-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import java.util.function.Function;
2525

2626
import org.springframework.util.Assert;
27+
import org.springframework.util.StringUtils;
2728

2829
/**
2930
* A configuration property name composed of elements separated by dots. User created
@@ -195,19 +196,32 @@ public int getNumberOfElements() {
195196
}
196197

197198
/**
198-
* Create a new {@link ConfigurationPropertyName} by appending the given elements.
199-
* @param elements the elements to append
199+
* Create a new {@link ConfigurationPropertyName} by appending the given suffix.
200+
* @param suffix the elements to append
200201
* @return a new {@link ConfigurationPropertyName}
201202
* @throws InvalidConfigurationPropertyNameException if the result is not valid
202203
*/
203-
public ConfigurationPropertyName append(String elements) {
204-
if (elements == null) {
204+
public ConfigurationPropertyName append(String suffix) {
205+
if (!StringUtils.hasLength(suffix)) {
205206
return this;
206207
}
207-
Elements additionalElements = probablySingleElementOf(elements);
208+
Elements additionalElements = probablySingleElementOf(suffix);
208209
return new ConfigurationPropertyName(this.elements.append(additionalElements));
209210
}
210211

212+
/**
213+
* Create a new {@link ConfigurationPropertyName} by appending the given suffix.
214+
* @param suffix the elements to append
215+
* @return a new {@link ConfigurationPropertyName}
216+
* @since 2.5.0
217+
*/
218+
public ConfigurationPropertyName append(ConfigurationPropertyName suffix) {
219+
if (suffix == null) {
220+
return this;
221+
}
222+
return new ConfigurationPropertyName(this.elements.append(suffix.elements));
223+
}
224+
211225
/**
212226
* Return the parent of this {@link ConfigurationPropertyName} or
213227
* {@link ConfigurationPropertyName#EMPTY} if there is no parent.
@@ -232,6 +246,27 @@ public ConfigurationPropertyName chop(int size) {
232246
return new ConfigurationPropertyName(this.elements.chop(size));
233247
}
234248

249+
/**
250+
* Return a new {@link ConfigurationPropertyName} by based on this name offset by
251+
* specific element index. For example, {@code chop(1)} on the name {@code foo.bar}
252+
* will return {@code bar}.
253+
* @param offset the element offset
254+
* @return the sub name
255+
* @since 2.5.0
256+
*/
257+
public ConfigurationPropertyName subName(int offset) {
258+
if (offset == 0) {
259+
return this;
260+
}
261+
if (offset == getNumberOfElements()) {
262+
return EMPTY;
263+
}
264+
if (offset < 0 || offset > getNumberOfElements()) {
265+
throw new IndexOutOfBoundsException("Offset: " + offset + ", NumberOfElements: " + getNumberOfElements());
266+
}
267+
return new ConfigurationPropertyName(this.elements.subElements(offset));
268+
}
269+
235270
/**
236271
* Returns {@code true} if this element is an immediate parent of the specified name.
237272
* @param name the name to check
@@ -718,19 +753,31 @@ Elements append(Elements additional) {
718753
ElementType[] type = new ElementType[size];
719754
System.arraycopy(this.type, 0, type, 0, this.size);
720755
System.arraycopy(additional.type, 0, type, this.size, additional.size);
721-
CharSequence[] resolved = newResolved(size);
756+
CharSequence[] resolved = newResolved(0, size);
722757
for (int i = 0; i < additional.size; i++) {
723758
resolved[this.size + i] = additional.get(i);
724759
}
725760
return new Elements(this.source, size, this.start, this.end, type, resolved);
726761
}
727762

728763
Elements chop(int size) {
729-
CharSequence[] resolved = newResolved(size);
764+
CharSequence[] resolved = newResolved(0, size);
730765
return new Elements(this.source, size, this.start, this.end, this.type, resolved);
731766
}
732767

733-
private CharSequence[] newResolved(int size) {
768+
Elements subElements(int offset) {
769+
int size = this.size - offset;
770+
CharSequence[] resolved = newResolved(offset, size);
771+
int[] start = new int[size];
772+
System.arraycopy(this.start, offset, start, 0, size);
773+
int[] end = new int[size];
774+
System.arraycopy(this.end, offset, end, 0, size);
775+
ElementType[] type = new ElementType[size];
776+
System.arraycopy(this.type, offset, type, 0, size);
777+
return new Elements(this.source, size, start, end, type, resolved);
778+
}
779+
780+
private CharSequence[] newResolved(int offset, int size) {
734781
CharSequence[] resolved = new CharSequence[size];
735782
if (this.resolved != null) {
736783
System.arraycopy(this.resolved, 0, resolved, 0, Math.min(size, this.size));

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySource.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.boot.origin.OriginTrackedValue;
2222
import org.springframework.core.env.PropertySource;
23+
import org.springframework.util.StringUtils;
2324

2425
/**
2526
* A source of {@link ConfigurationProperty ConfigurationProperties}.
@@ -78,9 +79,10 @@ default ConfigurationPropertySource withAliases(ConfigurationPropertyNameAliases
7879
* Return a variant of this source that supports a prefix.
7980
* @param prefix the prefix for properties in the source
8081
* @return a {@link ConfigurationPropertySource} instance supporting a prefix
82+
* @since 2.5.0
8183
*/
8284
default ConfigurationPropertySource withPrefix(String prefix) {
83-
return new PrefixedConfigurationPropertySource(this, prefix);
85+
return (StringUtils.hasText(prefix)) ? new PrefixedConfigurationPropertySource(this, prefix) : this;
8486
}
8587

8688
/**

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/IterableConfigurationPropertySource.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import java.util.stream.Stream;
2222

2323
import org.springframework.boot.origin.OriginTrackedValue;
24+
import org.springframework.util.StringUtils;
2425

2526
/**
2627
* A {@link ConfigurationPropertySource} with a fully {@link Iterable} set of entries.
@@ -75,7 +76,7 @@ default IterableConfigurationPropertySource withAliases(ConfigurationPropertyNam
7576

7677
@Override
7778
default IterableConfigurationPropertySource withPrefix(String prefix) {
78-
return new PrefixedIterableConfigurationPropertySource(this, prefix);
79+
return (StringUtils.hasText(prefix)) ? new PrefixedIterableConfigurationPropertySource(this, prefix) : this;
7980
}
8081

8182
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySource.java

+8-13
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.boot.context.properties.source;
1818

1919
import org.springframework.util.Assert;
20-
import org.springframework.util.StringUtils;
2120

2221
/**
2322
* A {@link ConfigurationPropertySource} supporting a prefix.
@@ -28,13 +27,17 @@ class PrefixedConfigurationPropertySource implements ConfigurationPropertySource
2827

2928
private final ConfigurationPropertySource source;
3029

31-
private final String prefix;
30+
private final ConfigurationPropertyName prefix;
3231

3332
PrefixedConfigurationPropertySource(ConfigurationPropertySource source, String prefix) {
3433
Assert.notNull(source, "Source must not be null");
35-
Assert.notNull(prefix, "Prefix must not be null");
34+
Assert.hasText(prefix, "Prefix must not be empty");
3635
this.source = source;
37-
this.prefix = prefix;
36+
this.prefix = ConfigurationPropertyName.of(prefix);
37+
}
38+
39+
protected final ConfigurationPropertyName getPrefix() {
40+
return this.prefix;
3841
}
3942

4043
@Override
@@ -47,11 +50,7 @@ public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName
4750
}
4851

4952
private ConfigurationPropertyName getPrefixedName(ConfigurationPropertyName name) {
50-
if (!StringUtils.hasText(this.prefix)) {
51-
return name;
52-
}
53-
String prefix = this.prefix + ".";
54-
return ConfigurationPropertyName.of(prefix + name);
53+
return this.prefix.append(name);
5554
}
5655

5756
@Override
@@ -68,8 +67,4 @@ protected ConfigurationPropertySource getSource() {
6867
return this.source;
6968
}
7069

71-
protected String getPrefix() {
72-
return this.prefix;
73-
}
74-
7570
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PrefixedIterableConfigurationPropertySource.java

+5-13
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
import java.util.stream.Stream;
2020

21-
import org.springframework.util.StringUtils;
22-
2321
/**
2422
* An iterable {@link PrefixedConfigurationPropertySource}.
2523
*
@@ -34,17 +32,11 @@ class PrefixedIterableConfigurationPropertySource extends PrefixedConfigurationP
3432

3533
@Override
3634
public Stream<ConfigurationPropertyName> stream() {
37-
if (!StringUtils.hasText(getPrefix())) {
38-
return getSource().stream();
39-
}
40-
ConfigurationPropertyName prefix = ConfigurationPropertyName.of(getPrefix());
41-
return getSource().stream().map((propertyName) -> {
42-
if (prefix.isAncestorOf(propertyName)) {
43-
String name = propertyName.toString();
44-
return ConfigurationPropertyName.of(name.substring(getPrefix().length() + 1));
45-
}
46-
return propertyName;
47-
});
35+
return getSource().stream().map(this::stripPrefix);
36+
}
37+
38+
private ConfigurationPropertyName stripPrefix(ConfigurationPropertyName name) {
39+
return (getPrefix().isAncestorOf(name)) ? name.subName(getPrefix().getNumberOfElements()) : name;
4840
}
4941

5042
@Override

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySources.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
2424
import java.util.Random;
2525
import java.util.function.Function;
2626

27-
import org.springframework.boot.env.Prefixed;
27+
import org.springframework.boot.origin.OriginLookup;
2828
import org.springframework.core.env.ConfigurableEnvironment;
2929
import org.springframework.core.env.MutablePropertySources;
3030
import org.springframework.core.env.PropertySource;
@@ -64,8 +64,8 @@ private ConfigurationPropertySource adapt(PropertySource<?> source) {
6464
return result;
6565
}
6666
result = SpringConfigurationPropertySource.from(source);
67-
if (source instanceof Prefixed) {
68-
result = result.withPrefix(((Prefixed) source).getPrefix());
67+
if (source instanceof OriginLookup) {
68+
result = result.withPrefix(((OriginLookup<?>) source).getPrefix());
6969
}
7070
this.cache.put(source, result);
7171
return result;

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/Prefixed.java

-31
This file was deleted.

0 commit comments

Comments
 (0)