Add auto-trimming support to configtree sources
Update `ConfigTreePropertySource` with an option to automatically trim trailing new-line characters. Closes gh-23826
This commit is contained in:
		
							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 final boolean autoTrimTrailingNewLine; | ||||
| 
 | ||||
| 		private volatile byte[] content; | ||||
| 
 | ||||
| 		private final Origin origin; | ||||
| 
 | ||||
| 		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…
	
		Reference in New Issue