源码解析
public class OriginTrackedPropertiesLoader {
private final Resource resource;
public OriginTrackedPropertiesLoader(Resource resource) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
}
public Map<String, OriginTrackedValue> load() throws IOException {
return load(true);
}
Map<String, OriginTrackedValue> load(boolean expandLists) throws IOException {
try (CharacterReader reader = new CharacterReader(this.resource)) {
Map<String, OriginTrackedValue> result = new LinkedHashMap<>();
StringBuilder buffer = new StringBuilder();
while (reader.read()) {
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);
put(result, key + "[" + (index++) + "]", value);
if (!reader.isEndOfLine()) {
reader.read();
}
} while (!reader.isEndOfLine());
}
else {
OriginTrackedValue value = loadValue(buffer, reader, false);
put(result, key, value);
}
}
return result;
}
}
private String loadKey(StringBuilder buffer, CharacterReader reader) throws IOException {
buffer.setLength(0);
boolean previousWhitespace = false;
while (!reader.isEndOfLine()) {
if (reader.isPropertyDelimiter()) {
reader.read();
return buffer.toString();
}
if (!reader.isWhiteSpace() && previousWhitespace) {
return buffer.toString();
}
previousWhitespace = reader.isWhiteSpace();
buffer.append(reader.getCharacter());
reader.read();
}
return buffer.toString();
}
private OriginTrackedValue loadValue(StringBuilder buffer, CharacterReader reader, boolean splitLists)
throws IOException {
buffer.setLength(0);
while (reader.isWhiteSpace() && !reader.isEndOfLine()) {
reader.read();
}
Location location = reader.getLocation();
while (!reader.isEndOfLine() && !(splitLists && reader.isListDelimiter())) {
buffer.append(reader.getCharacter());
reader.read();
}
Origin origin = new TextResourceOrigin(this.resource, location);
return OriginTrackedValue.of(buffer.toString(), origin);
}
private static class CharacterReader implements Closeable{
}
}
案例
test-properties.properties配置文件
# foo
blah = hello world
bar foo=baz
hello world
proper\\ty=test
foo
bat = a\\
bling = a=b
#commented-property=test
test=properties
test-unicode=properties\u0026test
# comment ending \
test\=property=helloworld
test-colon-separator: my-property
test-tab-property=foo\tbar
test-return-property=foo\rbar
test-newline-property=foo\nbar
test-form-feed-property=foo\fbar
test-whitespace-property = foo bar
test-multiline= a\
b\\\
c
foods[]=Apple,\
Orange,\
Strawberry,\
Mango
languages[perl]=Elite
languages[python]=Elite
language[pascal]=Lame
test-multiline-immediate=\
foo
!commented-two=bang\
test-bang-property=foo!
another=bar
test-property-value-comment=foo \
!bar #foo
test-multiline-immediate-bang=\
!foo
#test ISO 8859-1
test-iso8859-1-chars=����������
test-with-trailing-space= trailing
private ClassPathResource resource;
private Map<String, OriginTrackedValue> properties;
@Test
void compareToJavaProperties() throws Exception {
String path = "test-properties.properties";
this.resource = new ClassPathResource(path, getClass());
this.properties = new OriginTrackedPropertiesLoader(this.resource).load();
Properties java = PropertiesLoaderUtils.loadProperties(this.resource);
Properties ours = new Properties();
new OriginTrackedPropertiesLoader(this.resource)
.load(false)
.forEach((k, v) -> System.out.println(k+":"+v.getValue()));
}
运行结果
blah:hello world
bar:foo=baz
hello:world
proper\ty:test
foo:
bat:a\
bling:a=b
test:properties
test-unicode:properties&test
test=property:helloworld
test-colon-separator:my-property
test-tab-property:foo bar
bar
test-newline-property:foo
bar
test-form-feed-property:foobar
test-whitespace-property:foo bar
test-multiline:ab\c
foods[]:Apple,Orange,Strawberry,Mango
languages[perl]:Elite
languages[python]:Elite
language[pascal]:Lame
test-multiline-immediate:foo
test-bang-property:foo!
another:bar
test-property-value-comment:foo !bar
test-multiline-immediate-bang:!foo
test-iso8859-1-chars:����������
test-with-trailing-space:trailing