Skip to content

Commit cf673ce

Browse files
committed
Use stricter document properties separator logic
Update `OriginTrackedPropertiesLoader` with stricter logic around the document separator. If the preceding or following lines are comments then the separator will be ignored. Closes gh-22963
1 parent 0588e98 commit cf673ce

File tree

4 files changed

+71
-22
lines changed

4 files changed

+71
-22
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,8 @@ For `application.properties` files a special `#---` comment is used to mark the
886886
spring.application.name=MyCloudApp
887887
----
888888

889-
NOTE: Property file separators must not have any leading or trailing whitespace and must have exactly three hyphen characters.
889+
NOTE: Property file separators must not have any leading whitespace and must have exactly three hyphen characters.
890+
The lines immediately before and after the separator must not be comments.
890891

891892
TIP: Multi-document property files are often used in conjunction with activation properties such as `spring.config.activate.on-profile`.
892893
See the <<boot-features-external-config-file-activation-properties, next section>> for details.

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

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,46 +73,58 @@ List<Document> load() throws IOException {
7373
* @throws IOException on read error
7474
*/
7575
List<Document> load(boolean expandLists) throws IOException {
76-
List<Document> result = new ArrayList<>();
76+
List<Document> documents = new ArrayList<>();
7777
Document document = new Document();
78+
StringBuilder buffer = new StringBuilder();
7879
try (CharacterReader reader = new CharacterReader(this.resource)) {
79-
StringBuilder buffer = new StringBuilder();
8080
while (reader.read()) {
8181
if (reader.isPoundCharacter()) {
8282
if (isNewDocument(reader)) {
8383
if (!document.isEmpty()) {
84-
result.add(document);
84+
documents.add(document);
8585
}
8686
document = new Document();
8787
}
8888
else {
89-
reader.skipComment();
90-
}
91-
}
92-
String key = loadKey(buffer, reader).trim();
93-
if (expandLists && key.endsWith("[]")) {
94-
key = key.substring(0, key.length() - 2);
95-
int index = 0;
96-
do {
97-
OriginTrackedValue value = loadValue(buffer, reader, true);
98-
document.put(key + "[" + (index++) + "]", value);
99-
if (!reader.isEndOfLine()) {
100-
reader.read();
89+
if (document.isEmpty() && !documents.isEmpty()) {
90+
document = documents.remove(documents.size() - 1);
10191
}
92+
reader.setLastLineComment(true);
93+
reader.skipComment();
10294
}
103-
while (!reader.isEndOfLine());
10495
}
10596
else {
106-
OriginTrackedValue value = loadValue(buffer, reader, false);
107-
document.put(key, value);
97+
reader.setLastLineComment(false);
98+
loadKeyAndValue(expandLists, document, reader, buffer);
10899
}
109100
}
110101

111102
}
112-
if (!document.isEmpty() && !result.contains(document)) {
113-
result.add(document);
103+
if (!document.isEmpty() && !documents.contains(document)) {
104+
documents.add(document);
105+
}
106+
return documents;
107+
}
108+
109+
private void loadKeyAndValue(boolean expandLists, Document document, CharacterReader reader, StringBuilder buffer)
110+
throws IOException {
111+
String key = loadKey(buffer, reader).trim();
112+
if (expandLists && key.endsWith("[]")) {
113+
key = key.substring(0, key.length() - 2);
114+
int index = 0;
115+
do {
116+
OriginTrackedValue value = loadValue(buffer, reader, true);
117+
document.put(key + "[" + (index++) + "]", value);
118+
if (!reader.isEndOfLine()) {
119+
reader.read();
120+
}
121+
}
122+
while (!reader.isEndOfLine());
123+
}
124+
else {
125+
OriginTrackedValue value = loadValue(buffer, reader, false);
126+
document.put(key, value);
114127
}
115-
return result;
116128
}
117129

118130
private String loadKey(StringBuilder buffer, CharacterReader reader) throws IOException {
@@ -149,6 +161,9 @@ private OriginTrackedValue loadValue(StringBuilder buffer, CharacterReader reade
149161
}
150162

151163
boolean isNewDocument(CharacterReader reader) throws IOException {
164+
if (reader.isLastLineComment()) {
165+
return false;
166+
}
152167
boolean result = reader.getLocation().getColumn() == 0 && reader.isPoundCharacter();
153168
result = result && readAndExpect(reader, reader::isHyphenCharacter);
154169
result = result && readAndExpect(reader, reader::isHyphenCharacter);
@@ -179,6 +194,8 @@ private static class CharacterReader implements Closeable {
179194

180195
private int character;
181196

197+
private boolean lastLineComment;
198+
182199
CharacterReader(Resource resource) throws IOException {
183200
this.reader = new LineNumberReader(
184201
new InputStreamReader(resource.getInputStream(), StandardCharsets.ISO_8859_1));
@@ -222,6 +239,14 @@ private void skipWhitespace() throws IOException {
222239
}
223240
}
224241

242+
private void setLastLineComment(boolean lastLineComment) {
243+
this.lastLineComment = lastLineComment;
244+
}
245+
246+
private boolean isLastLineComment() {
247+
return this.lastLineComment;
248+
}
249+
225250
private void skipComment() throws IOException {
226251
while (this.character != '\n' && this.character != -1) {
227252
this.character = this.reader.read();

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,13 @@ void getPropertyWithEscapedTrailingSpace() {
286286
assertThat(getValue(value)).isEqualTo("trailing ");
287287
}
288288

289+
@Test
290+
void existingCommentsAreNotTreatedAsMultiDoc() throws Exception {
291+
this.resource = new ClassPathResource("existing-non-multi-document.properties", getClass());
292+
this.documents = new OriginTrackedPropertiesLoader(this.resource).load();
293+
assertThat(this.documents.size()).isEqualTo(1);
294+
}
295+
289296
private OriginTrackedValue getFromFirst(String key) {
290297
return this.documents.get(0).asMap().get(key);
291298
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#---
2+
# Test
3+
#---
4+
5+
spring=boot
6+
7+
#---
8+
# Test
9+
10+
boot=bar
11+
12+
13+
# Test
14+
#---
15+
16+
bar=ok

0 commit comments

Comments
 (0)