Add auto-trimming support to configtree sources

Update `ConfigTreePropertySource` with an option to automatically trim
trailing new-line characters.

Closes gh-23826
pull/28993/head
Phillip Webb 4 years ago
parent cf673cee55
commit 2e2b371679

@ -21,6 +21,7 @@ import java.nio.file.Path;
import java.util.Collections;
import org.springframework.boot.env.ConfigTreePropertySource;
import org.springframework.boot.env.ConfigTreePropertySource.Option;
/**
* {@link ConfigDataLoader} for config tree locations.
@ -37,7 +38,7 @@ public class ConfigTreeConfigDataLoader implements ConfigDataLoader<ConfigTreeCo
Path path = resource.getPath();
ConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, path);
String name = "Config tree '" + path + "'";
ConfigTreePropertySource source = new ConfigTreePropertySource(name, path);
ConfigTreePropertySource source = new ConfigTreePropertySource(name, path, Option.AUTO_TRIM_TRAILING_NEW_LINE);
return new ConfigData(Collections.singletonList(source));
}

@ -145,7 +145,12 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
/**
* Convert file and directory names to lowercase.
*/
USE_LOWERCASE_NAMES
USE_LOWERCASE_NAMES,
/**
* Automatically attempt trim trailing new-line characters.
*/
AUTO_TRIM_TRAILING_NEW_LINE
}
@ -173,17 +178,22 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
private final PropertyFileContent cachedContent;
private final boolean autoTrimTrailingNewLine;
private PropertyFile(Path path, Set<Option> options) {
this.path = path;
this.resource = new PathResource(path);
this.origin = new TextResourceOrigin(this.resource, START_OF_FILE);
this.autoTrimTrailingNewLine = options.contains(Option.AUTO_TRIM_TRAILING_NEW_LINE);
this.cachedContent = options.contains(Option.ALWAYS_READ) ? null
: new PropertyFileContent(path, this.resource, this.origin, true);
: new PropertyFileContent(path, this.resource, this.origin, true, this.autoTrimTrailingNewLine);
}
PropertyFileContent getContent() {
return (this.cachedContent != null) ? this.cachedContent
: new PropertyFileContent(this.path, this.resource, this.origin, false);
if (this.cachedContent != null) {
return this.cachedContent;
}
return new PropertyFileContent(this.path, this.resource, this.origin, false, this.autoTrimTrailingNewLine);
}
Origin getOrigin() {
@ -247,17 +257,21 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
private final Resource resource;
private final Origin origin;
private final boolean cacheContent;
private volatile byte[] content;
private final boolean autoTrimTrailingNewLine;
private final Origin origin;
private volatile byte[] content;
private PropertyFileContent(Path path, Resource resource, Origin origin, boolean cacheContent) {
private PropertyFileContent(Path path, Resource resource, Origin origin, boolean cacheContent,
boolean autoTrimTrailingNewLine) {
this.path = path;
this.resource = resource;
this.origin = origin;
this.cacheContent = cacheContent;
this.autoTrimTrailingNewLine = autoTrimTrailingNewLine;
}
@Override
@ -282,7 +296,28 @@ public class ConfigTreePropertySource extends EnumerablePropertySource<Path> imp
@Override
public String toString() {
return new String(getBytes());
String string = new String(getBytes());
if (this.autoTrimTrailingNewLine) {
string = autoTrimTrailingNewLine(string);
}
return string;
}
private String autoTrimTrailingNewLine(String string) {
if (!string.endsWith("\n")) {
return string;
}
int numberOfLines = 0;
for (char ch : string.toCharArray()) {
if (ch == '\n') {
numberOfLines++;
}
}
if (numberOfLines > 1) {
return string;
}
return (string.endsWith("\r\n")) ? string.substring(0, string.length() - 2)
: string.substring(0, string.length() - 1);
}
@Override

@ -50,7 +50,7 @@ public class ConfigTreeConfigDataLoaderTests {
void loadReturnsConfigDataWithPropertySource() throws IOException {
File file = this.directory.resolve("hello").toFile();
file.getParentFile().mkdirs();
FileCopyUtils.copy("world".getBytes(StandardCharsets.UTF_8), file);
FileCopyUtils.copy("world\n".getBytes(StandardCharsets.UTF_8), file);
ConfigTreeConfigDataResource location = new ConfigTreeConfigDataResource(this.directory.toString());
ConfigData configData = this.loader.load(this.loaderContext, location);
assertThat(configData.getPropertySources().size()).isEqualTo(1);

@ -199,6 +199,30 @@ class ConfigTreePropertySourceTests {
assertThat(propertySource.getProperty("spring")).hasToString("boot");
}
@Test
void getPropertyAsStringWhenMultiLinePropertyReturnsNonTrimmed() throws Exception {
addProperty("a", "a\nb\n");
ConfigTreePropertySource propertySource = new ConfigTreePropertySource("test", this.directory,
Option.AUTO_TRIM_TRAILING_NEW_LINE);
assertThat(propertySource.getProperty("a").toString()).isEqualTo("a\nb\n");
}
@Test
void getPropertyAsStringWhenPropertyEndsWithNewLineReturnsTrimmed() throws Exception {
addProperty("a", "a\n");
ConfigTreePropertySource propertySource = new ConfigTreePropertySource("test", this.directory,
Option.AUTO_TRIM_TRAILING_NEW_LINE);
assertThat(propertySource.getProperty("a").toString()).isEqualTo("a");
}
@Test
void getPropertyAsStringWhenPropertyEndsWithWindowsNewLineReturnsTrimmed() throws Exception {
addProperty("a", "a\r\n");
ConfigTreePropertySource propertySource = new ConfigTreePropertySource("test", this.directory,
Option.AUTO_TRIM_TRAILING_NEW_LINE);
assertThat(propertySource.getProperty("a").toString()).isEqualTo("a");
}
private ConfigTreePropertySource getFlatPropertySource() throws IOException {
addProperty("a", "A");
addProperty("b", "B");

Loading…
Cancel
Save