源码解析
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