diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 76867dcf99..c1a01de779 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -886,7 +886,8 @@ For `application.properties` files a special `#---` comment is used to mark the spring.application.name=MyCloudApp ---- -NOTE: Property file separators must not have any leading or trailing whitespace and must have exactly three hyphen characters. +NOTE: Property file separators must not have any leading whitespace and must have exactly three hyphen characters. +The lines immediately before and after the separator must not be comments. TIP: Multi-document property files are often used in conjunction with activation properties such as `spring.config.activate.on-profile`. See the <> for details. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedPropertiesLoader.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedPropertiesLoader.java index f84e0c28ec..96ee296bfb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedPropertiesLoader.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedPropertiesLoader.java @@ -73,46 +73,58 @@ class OriginTrackedPropertiesLoader { * @throws IOException on read error */ List load(boolean expandLists) throws IOException { - List result = new ArrayList<>(); + List documents = new ArrayList<>(); Document document = new Document(); + StringBuilder buffer = new StringBuilder(); try (CharacterReader reader = new CharacterReader(this.resource)) { - StringBuilder buffer = new StringBuilder(); while (reader.read()) { if (reader.isPoundCharacter()) { if (isNewDocument(reader)) { if (!document.isEmpty()) { - result.add(document); + documents.add(document); } document = new Document(); } else { + if (document.isEmpty() && !documents.isEmpty()) { + document = documents.remove(documents.size() - 1); + } + reader.setLastLineComment(true); reader.skipComment(); } } - String key = loadKey(buffer, reader).trim(); - if (expandLists && key.endsWith("[]")) { - key = key.substring(0, key.length() - 2); - int index = 0; - do { - OriginTrackedValue value = loadValue(buffer, reader, true); - document.put(key + "[" + (index++) + "]", value); - if (!reader.isEndOfLine()) { - reader.read(); - } - } - while (!reader.isEndOfLine()); - } else { - OriginTrackedValue value = loadValue(buffer, reader, false); - document.put(key, value); + reader.setLastLineComment(false); + loadKeyAndValue(expandLists, document, reader, buffer); } } } - if (!document.isEmpty() && !result.contains(document)) { - result.add(document); + if (!document.isEmpty() && !documents.contains(document)) { + documents.add(document); + } + return documents; + } + + private void loadKeyAndValue(boolean expandLists, Document document, CharacterReader reader, StringBuilder buffer) + throws IOException { + String key = loadKey(buffer, reader).trim(); + if (expandLists && key.endsWith("[]")) { + key = key.substring(0, key.length() - 2); + int index = 0; + do { + OriginTrackedValue value = loadValue(buffer, reader, true); + document.put(key + "[" + (index++) + "]", value); + if (!reader.isEndOfLine()) { + reader.read(); + } + } + while (!reader.isEndOfLine()); + } + else { + OriginTrackedValue value = loadValue(buffer, reader, false); + document.put(key, value); } - return result; } private String loadKey(StringBuilder buffer, CharacterReader reader) throws IOException { @@ -149,6 +161,9 @@ class OriginTrackedPropertiesLoader { } boolean isNewDocument(CharacterReader reader) throws IOException { + if (reader.isLastLineComment()) { + return false; + } boolean result = reader.getLocation().getColumn() == 0 && reader.isPoundCharacter(); result = result && readAndExpect(reader, reader::isHyphenCharacter); result = result && readAndExpect(reader, reader::isHyphenCharacter); @@ -179,6 +194,8 @@ class OriginTrackedPropertiesLoader { private int character; + private boolean lastLineComment; + CharacterReader(Resource resource) throws IOException { this.reader = new LineNumberReader( new InputStreamReader(resource.getInputStream(), StandardCharsets.ISO_8859_1)); @@ -222,6 +239,14 @@ class OriginTrackedPropertiesLoader { } } + private void setLastLineComment(boolean lastLineComment) { + this.lastLineComment = lastLineComment; + } + + private boolean isLastLineComment() { + return this.lastLineComment; + } + private void skipComment() throws IOException { while (this.character != '\n' && this.character != -1) { this.character = this.reader.read(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java index e13b4990b0..971c425bfa 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java @@ -286,6 +286,13 @@ class OriginTrackedPropertiesLoaderTests { assertThat(getValue(value)).isEqualTo("trailing "); } + @Test + void existingCommentsAreNotTreatedAsMultiDoc() throws Exception { + this.resource = new ClassPathResource("existing-non-multi-document.properties", getClass()); + this.documents = new OriginTrackedPropertiesLoader(this.resource).load(); + assertThat(this.documents.size()).isEqualTo(1); + } + private OriginTrackedValue getFromFirst(String key) { return this.documents.get(0).asMap().get(key); } diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/env/existing-non-multi-document.properties b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/env/existing-non-multi-document.properties new file mode 100644 index 0000000000..b5e003745c --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/env/existing-non-multi-document.properties @@ -0,0 +1,16 @@ +#--- +# Test +#--- + +spring=boot + +#--- +# Test + +boot=bar + + +# Test +#--- + +bar=ok