Skip to content

Commit

Permalink
Use exclamation character for the document separator prefix
Browse files Browse the repository at this point in the history
Closes gh-32185
  • Loading branch information
terminux committed Sep 29, 2022
1 parent 1e886bd commit 17ff3f1
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 32 deletions.
Expand Up @@ -497,7 +497,7 @@ For example, the following file has two logical documents:
on-cloud-platform: "kubernetes"
----

For `application.properties` files a special `#---` comment is used to mark the document splits:
For `application.properties` files a special `#---` or `!---` comment is used to mark the document splits:

[source,properties,indent=0,subs="verbatim"]
----
Expand All @@ -508,7 +508,7 @@ For `application.properties` files a special `#---` comment is used to mark the
----

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.
The lines immediately before and after the separator must not be same comment prefix.

TIP: Multi-document property files are often used in conjunction with activation properties such as `spring.config.activate.on-profile`.
See the <<features#features.external-config.files.activation-properties, next section>> for details.
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
Expand Down Expand Up @@ -78,7 +78,8 @@ List<Document> load(boolean expandLists) throws IOException {
StringBuilder buffer = new StringBuilder();
try (CharacterReader reader = new CharacterReader(this.resource)) {
while (reader.read()) {
if (reader.isPoundCharacter()) {
if (reader.isCommentPrefixCharacter()) {
char commentPrefixCharacter = reader.getCharacter();
if (isNewDocument(reader)) {
if (!document.isEmpty()) {
documents.add(document);
Expand All @@ -89,12 +90,12 @@ List<Document> load(boolean expandLists) throws IOException {
if (document.isEmpty() && !documents.isEmpty()) {
document = documents.remove(documents.size() - 1);
}
reader.setLastLineComment(true);
reader.setLastLineCommentPrefix(commentPrefixCharacter);
reader.skipComment();
}
}
else {
reader.setLastLineComment(false);
reader.setLastLineCommentPrefix(-1);
loadKeyAndValue(expandLists, document, reader, buffer);
}
}
Expand Down Expand Up @@ -161,10 +162,10 @@ private OriginTrackedValue loadValue(StringBuilder buffer, CharacterReader reade
}

private boolean isNewDocument(CharacterReader reader) throws IOException {
if (reader.isLastLineComment()) {
if (reader.isSameLastLineCommentPrefix()) {
return false;
}
boolean result = reader.getLocation().getColumn() == 0 && reader.isPoundCharacter();
boolean result = reader.getLocation().getColumn() == 0;
result = result && readAndExpect(reader, reader::isHyphenCharacter);
result = result && readAndExpect(reader, reader::isHyphenCharacter);
result = result && readAndExpect(reader, reader::isHyphenCharacter);
Expand Down Expand Up @@ -196,7 +197,7 @@ private static class CharacterReader implements Closeable {

private int character;

private boolean lastLineComment;
private int lastLineCommentPrefix;

CharacterReader(Resource resource) throws IOException {
this.reader = new LineNumberReader(
Expand All @@ -209,20 +210,11 @@ public void close() throws IOException {
}

boolean read() throws IOException {
return read(false);
}

boolean read(boolean wrappedLine) throws IOException {
this.escaped = false;
this.character = this.reader.read();
this.columnNumber++;
if (this.columnNumber == 0) {
skipWhitespace();
if (!wrappedLine) {
if (this.character == '!') {
skipComment();
}
}
}
if (this.character == '\\') {
this.escaped = true;
Expand All @@ -241,12 +233,8 @@ private void skipWhitespace() throws IOException {
}
}

private void setLastLineComment(boolean lastLineComment) {
this.lastLineComment = lastLineComment;
}

private boolean isLastLineComment() {
return this.lastLineComment;
private void setLastLineCommentPrefix(int lastLineCommentPrefix) {
this.lastLineCommentPrefix = lastLineCommentPrefix;
}

private void skipComment() throws IOException {
Expand All @@ -264,7 +252,7 @@ private void readEscaped() throws IOException {
}
else if (this.character == '\n') {
this.columnNumber = -1;
read(true);
read();
}
else if (this.character == 'u') {
readUnicode();
Expand Down Expand Up @@ -318,8 +306,12 @@ Location getLocation() {
return new Location(this.reader.getLineNumber(), this.columnNumber);
}

boolean isPoundCharacter() {
return this.character == '#';
boolean isSameLastLineCommentPrefix() {
return this.lastLineCommentPrefix == this.character;
}

boolean isCommentPrefixCharacter() {
return this.character == '#' || this.character == '!';
}

boolean isHyphenCharacter() {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
Expand Down Expand Up @@ -183,33 +183,70 @@ void getImmediateMultiline() {
}

@Test
void loadWhenMultiDocumentWithoutWhitespaceLoadsMultiDoc() throws IOException {
void loadWhenMultiDocumentWithPoundPrefixAndWithoutWhitespaceLoadsMultiDoc() throws IOException {
String content = "a=a\n#---\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(2);
}

@Test
void loadWhenMultiDocumentWithLeadingWhitespaceLoadsSingleDoc() throws IOException {
void loadWhenMultiDocumentWithExclamationPrefixAndWithoutWhitespaceLoadsMultiDoc() throws IOException {
String content = "a=a\n!---\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(2);
}

@Test
void loadWhenMultiDocumentWithPoundPrefixAndLeadingWhitespaceLoadsSingleDoc() throws IOException {
String content = "a=a\n \t#---\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(1);
}

@Test
void loadWhenMultiDocumentWithTrailingWhitespaceLoadsMultiDoc() throws IOException {
void loadWhenMultiDocumentWithExclamationPrefixAndLeadingWhitespaceLoadsSingleDoc() throws IOException {
String content = "a=a\n \t!---\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(1);
}

@Test
void loadWhenMultiDocumentWithPoundPrefixAndTrailingWhitespaceLoadsMultiDoc() throws IOException {
String content = "a=a\n#--- \t \nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(2);
}

@Test
void loadWhenMultiDocumentWithTrailingCharsLoadsSingleDoc() throws IOException {
void loadWhenMultiDocumentWithExclamationPrefixAndTrailingWhitespaceLoadsMultiDoc() throws IOException {
String content = "a=a\n!--- \t \nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(2);
}

@Test
void loadWhenMultiDocumentWithPoundPrefixAndTrailingCharsLoadsSingleDoc() throws IOException {
String content = "a=a\n#--- \tcomment\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(1);
}

@Test
void loadWhenMultiDocumentWithExclamationPrefixAndTrailingCharsLoadsSingleDoc() throws IOException {
String content = "a=a\n!--- \tcomment\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(1);
}

@Test
void loadWhenMultiDocumentSeparatorPrefixDifferentFromCommentPrefixLoadsMultiDoc() throws IOException {
String[] contents = new String[] { "a=a\n# comment\n!---\nb=b", "a=a\n! comment\n#---\nb=b" };
for (String content : contents) {
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(2);
}
}

@Test
void getPropertyWithWhitespaceAfterKey() {
OriginTrackedValue value = getFromFirst("bar");
Expand Down
Expand Up @@ -14,3 +14,19 @@ boot=bar
#---

bar=ok

!---
! Test
!---

ok=well

!---
! Test

well=hello

! Test
!---

hello=world

0 comments on commit 17ff3f1

Please sign in to comment.