Allow trailing whitespace document split marker

Refine `OriginTrackedPropertiesLoader` document split detection to be
more lenient if there is trailing whitespace.

Closes gh-23399
pull/23418/head
Phillip Webb 4 years ago
parent 90483d343f
commit 8b8d5ccb10

@ -57,8 +57,7 @@ class OriginTrackedPropertiesLoader {
} }
/** /**
* Load {@code .properties} data and return a map of {@code String} -> * Load {@code .properties} data and return a list of documents.
* {@link OriginTrackedValue}.
* @return the loaded properties * @return the loaded properties
* @throws IOException on read error * @throws IOException on read error
*/ */
@ -79,7 +78,7 @@ class OriginTrackedPropertiesLoader {
try (CharacterReader reader = new CharacterReader(this.resource)) { try (CharacterReader reader = new CharacterReader(this.resource)) {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
while (reader.read()) { while (reader.read()) {
if (reader.getCharacter() == '#') { if (reader.isPoundCharacter()) {
if (isNewDocument(reader)) { if (isNewDocument(reader)) {
if (!document.isEmpty()) { if (!document.isEmpty()) {
result.add(document); result.add(document);
@ -150,12 +149,13 @@ class OriginTrackedPropertiesLoader {
} }
boolean isNewDocument(CharacterReader reader) throws IOException { boolean isNewDocument(CharacterReader reader) throws IOException {
boolean result = reader.isPoundCharacter(); boolean result = reader.getLocation().getColumn() == 0 && reader.isPoundCharacter();
result = result && readAndExpect(reader, reader::isHyphenCharacter); result = result && readAndExpect(reader, reader::isHyphenCharacter);
result = result && readAndExpect(reader, reader::isHyphenCharacter); result = result && readAndExpect(reader, reader::isHyphenCharacter);
result = result && readAndExpect(reader, reader::isHyphenCharacter); result = result && readAndExpect(reader, reader::isHyphenCharacter);
result = result && readAndExpect(reader, reader::isEndOfLine); reader.read();
return result; reader.skipWhitespace();
return result && reader.isEndOfLine();
} }
private boolean readAndExpect(CharacterReader reader, BooleanSupplier check) throws IOException { private boolean readAndExpect(CharacterReader reader, BooleanSupplier check) throws IOException {
@ -198,7 +198,7 @@ class OriginTrackedPropertiesLoader {
this.character = this.reader.read(); this.character = this.reader.read();
this.columnNumber++; this.columnNumber++;
if (this.columnNumber == 0) { if (this.columnNumber == 0) {
skipLeadingWhitespace(); skipWhitespace();
if (!wrappedLine) { if (!wrappedLine) {
if (this.character == '!') { if (this.character == '!') {
skipComment(); skipComment();
@ -215,7 +215,7 @@ class OriginTrackedPropertiesLoader {
return !isEndOfFile(); return !isEndOfFile();
} }
private void skipLeadingWhitespace() throws IOException { private void skipWhitespace() throws IOException {
while (isWhiteSpace()) { while (isWhiteSpace()) {
this.character = this.reader.read(); this.character = this.reader.read();
this.columnNumber++; this.columnNumber++;

@ -16,6 +16,7 @@
package org.springframework.boot.env; package org.springframework.boot.env;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
@ -25,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.env.OriginTrackedPropertiesLoader.Document; import org.springframework.boot.env.OriginTrackedPropertiesLoader.Document;
import org.springframework.boot.origin.OriginTrackedValue; import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin; import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.core.io.support.PropertiesLoaderUtils;
@ -180,6 +182,34 @@ class OriginTrackedPropertiesLoaderTests {
assertThat(getLocation(value)).isEqualTo("32:1"); assertThat(getLocation(value)).isEqualTo("32:1");
} }
@Test
void loadWhenMultiDocumentWithoutWhitespaceLoadsMultiDoc() 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 {
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 {
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 {
String content = "a=a\n#--- \tcomment\nb=b";
List<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load();
assertThat(loaded).hasSize(1);
}
@Test @Test
void getPropertyWithWhitespaceAfterKey() { void getPropertyWithWhitespaceAfterKey() {
OriginTrackedValue value = getFromFirst("bar"); OriginTrackedValue value = getFromFirst("bar");

Loading…
Cancel
Save