Configure SnakeYAML so the timestamp-like strings do not become Dates

By default, SnakeYAML will convert a timestamp-like string into a
java.util.Date. This differs to properties file-based configuration
where the values are always strings. Dates are problematic as the
round trip (string -> Date -> string) can change the value. For example,
“2015-01-27” becomes “Tue Jan 27 00:00:00 GMT 2015”.

This commit updates YamlPropertySourceLoader to use a Yaml with a
custom Resolver subclass that suppresses the addition of the implicit
resolver for timestamps. Supressing the addition of the unwanted
resolver, rather than overriding addImplicitResolvers and registering
the resolvers that we do want, ensures that we get all of the other
default Resolvers in their default order.

Fixes gh-2422
This commit is contained in:
Andy Wilkinson 2015-01-29 11:02:24 +00:00
parent 54e90c03fc
commit 68c7c65d52
3 changed files with 34 additions and 3 deletions

View File

@ -111,7 +111,7 @@
<snakeyaml.version>1.14</snakeyaml.version>
<solr.version>4.7.2</solr.version>
<spock.version>0.7-groovy-2.0</spock.version>
<spring.version>4.1.4.RELEASE</spring.version>
<spring.version>4.1.5.BUILD-SNAPSHOT</spring.version>
<spring-amqp.version>1.4.2.RELEASE</spring-amqp.version>
<spring-cloud-connectors.version>1.1.1.RELEASE</spring-cloud-connectors.version>
<spring-batch.version>3.0.2.RELEASE</spring-batch.version>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;
import org.springframework.beans.factory.config.YamlProcessor;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
@ -28,12 +29,18 @@ import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.resolver.Resolver;
/**
* Strategy to load '.yml' (or '.yaml') files into a {@link PropertySource}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class YamlPropertySourceLoader implements PropertySourceLoader {
@ -73,6 +80,21 @@ public class YamlPropertySourceLoader implements PropertySourceLoader {
setResources(new Resource[] { resource });
}
@Override
protected Yaml createYaml() {
return new Yaml(new StrictMapAppenderConstructor(), new Representer(),
new DumperOptions(), new Resolver() {
@Override
public void addImplicitResolver(Tag tag, Pattern regexp,
String first) {
if (tag == Tag.TIMESTAMP) {
return;
}
super.addImplicitResolver(tag, regexp, first);
}
});
}
public Map<String, Object> process() {
final Map<String, Object> result = new LinkedHashMap<String, Object>();
process(new MatchCallback() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,6 +34,7 @@ import static org.junit.Assert.assertThat;
*
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class YamlPropertySourceLoaderTests {
@ -75,4 +76,12 @@ public class YamlPropertySourceLoaderTests {
assertEquals("wham", source.getProperty("foo.baz"));
}
@Test
public void timestampLikeItemsDoNotBecomeDates() throws Exception {
ByteArrayResource resource = new ByteArrayResource("foo: 2015-01-28".getBytes());
PropertySource<?> source = this.loader.load("resource", resource, null);
assertNotNull(source);
assertEquals("2015-01-28", source.getProperty("foo"));
}
}