Check for duplicate keys in YAML map nodes
Snake YAML allows for duplicate keys in map nodes. See https://code.google.com/p/snakeyaml/issues/detail?id=199 This commit uses a dedicated Constructor extension that explicitly checks for such duplicate keys. Issue: SPR-12318
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -25,10 +26,14 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -126,7 +131,7 @@ public abstract class YamlProcessor {
|
||||
* @param callback a callback to delegate to once matching documents are found
|
||||
*/
|
||||
protected void process(MatchCallback callback) {
|
||||
Yaml yaml = new Yaml();
|
||||
Yaml yaml = new Yaml(new StrictMapAppenderConstructor());
|
||||
for (Resource resource : this.resources) {
|
||||
boolean found = process(callback, yaml, resource);
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
|
||||
@@ -351,4 +356,44 @@ public abstract class YamlProcessor {
|
||||
FIRST_FOUND
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A specialized {@link Constructor} that checks for duplicate keys.
|
||||
*/
|
||||
private static class StrictMapAppenderConstructor extends Constructor {
|
||||
|
||||
public StrictMapAppenderConstructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Object, Object> constructMapping(MappingNode node) {
|
||||
try {
|
||||
return super.constructMapping(node);
|
||||
} catch (IllegalStateException e) {
|
||||
throw new ParserException("while parsing MappingNode",
|
||||
node.getStartMark(), e.getMessage(), node.getEndMark());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Object, Object> createDefaultMap() {
|
||||
final Map<Object, Object> delegate = super.createDefaultMap();
|
||||
return new AbstractMap<Object, Object>() {
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
if (delegate.containsKey(key)) {
|
||||
throw new IllegalStateException("duplicate key: " + key);
|
||||
}
|
||||
return delegate.put(key, value);
|
||||
}
|
||||
@Override
|
||||
public Set<Entry<Object, Object>> entrySet() {
|
||||
return delegate.entrySet();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user