aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Somov <public.somov@gmail.com>2022-09-10 12:54:02 +0300
committerAndrey Somov <public.somov@gmail.com>2022-09-10 12:54:02 +0300
commit1c934251f9de51ce1e86bb80a86f46d235744274 (patch)
tree7f76ebc000d1d2d9a9582660d333079f053367b0
parent5056a448f09c46250346c338e821386caa751182 (diff)
downloadsnakeyaml-1c934251f9de51ce1e86bb80a86f46d235744274.tar.gz
Reformat constructor package
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java26
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java1076
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/Construct.java43
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/Constructor.java1182
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java19
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java29
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/DuplicateKeyException.java9
-rw-r--r--src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java1042
8 files changed, 1727 insertions, 1699 deletions
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java b/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
index d302bd89..6f4a1183 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
@@ -24,18 +24,18 @@ import org.yaml.snakeyaml.nodes.Node;
*/
public abstract class AbstractConstruct implements Construct {
- /**
- * Fail with a reminder to provide the seconds step for a recursive
- * structure
- *
- * @see org.yaml.snakeyaml.constructor.Construct#construct2ndStep(org.yaml.snakeyaml.nodes.Node,
- * java.lang.Object)
- */
- public void construct2ndStep(Node node, Object data) {
- if (node.isTwoStepsConstruction()) {
- throw new IllegalStateException("Not Implemented in " + getClass().getName());
- } else {
- throw new YAMLException("Unexpected recursive structure for Node: " + node);
- }
+ /**
+ * Fail with a reminder to provide the seconds step for a recursive
+ * structure
+ *
+ * @see org.yaml.snakeyaml.constructor.Construct#construct2ndStep(org.yaml.snakeyaml.nodes.Node,
+ * java.lang.Object)
+ */
+ public void construct2ndStep(Node node, Object data) {
+ if (node.isTwoStepsConstruction()) {
+ throw new IllegalStateException("Not Implemented in " + getClass().getName());
+ } else {
+ throw new YAMLException("Unexpected recursive structure for Node: " + node);
}
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
index 454ea4c9..485b6f81 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
@@ -32,7 +32,6 @@ import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
-
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.composer.Composer;
@@ -49,568 +48,573 @@ import org.yaml.snakeyaml.nodes.SequenceNode;
import org.yaml.snakeyaml.nodes.Tag;
public abstract class BaseConstructor {
- /**
- * It maps the node kind to the the Construct implementation. When the
- * runtime class is known then the implicit tag is ignored.
- */
- protected final Map<NodeId, Construct> yamlClassConstructors = new EnumMap<NodeId, Construct>(
- NodeId.class);
- /**
- * It maps the (explicit or implicit) tag to the Construct implementation.
- * It is used:
- * 1) explicit tag - if present.
- * 2) implicit tag - when the runtime class of the instance is unknown (the
- * node has the Object.class)
- */
- protected final Map<Tag, Construct> yamlConstructors = new HashMap<Tag, Construct>();
- /**
- * It maps the (explicit or implicit) tag to the Construct implementation.
- * It is used when no exact match found.
- */
- protected final Map<String, Construct> yamlMultiConstructors = new HashMap<String, Construct>();
-
- protected Composer composer;
- final Map<Node, Object> constructedObjects;
- private final Set<Node> recursiveObjects;
- private final ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>> maps2fill;
- private final ArrayList<RecursiveTuple<Set<Object>, Object>> sets2fill;
-
- protected Tag rootTag;
- private PropertyUtils propertyUtils;
- private boolean explicitPropertyUtils;
- private boolean allowDuplicateKeys = true;
- private boolean wrappedToRootException = false;
-
- private boolean enumCaseSensitive = false;
-
- protected final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
- protected final Map<Tag, Class<? extends Object>> typeTags;
-
- protected LoaderOptions loadingConfig;
-
- public BaseConstructor() {
- this(new LoaderOptions());
- }
-
- public BaseConstructor(LoaderOptions loadingConfig) {
- constructedObjects = new HashMap<Node, Object>();
- recursiveObjects = new HashSet<Node>();
- maps2fill = new ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>>();
- sets2fill = new ArrayList<RecursiveTuple<Set<Object>, Object>>();
- typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
- typeTags = new HashMap<Tag, Class<? extends Object>>();
-
- rootTag = null;
- explicitPropertyUtils = false;
-
- typeDefinitions.put(SortedMap.class, new TypeDescription(SortedMap.class, Tag.OMAP,
- TreeMap.class));
- typeDefinitions.put(SortedSet.class, new TypeDescription(SortedSet.class, Tag.SET,
- TreeSet.class));
- this.loadingConfig = loadingConfig;
- }
-
- public void setComposer(Composer composer) {
- this.composer = composer;
- }
-
- /**
- * Check if more documents available
- *
- * @return true when there are more YAML documents in the stream
- */
- public boolean checkData() {
- // If there are more documents available?
- return composer.checkNode();
- }
- /**
- * Construct and return the next document
- *
- * @return constructed instance
- */
- public Object getData() throws NoSuchElementException {
- // Construct and return the next document.
- if (!composer.checkNode()) throw new NoSuchElementException("No document is available.");
- Node node = composer.getNode();
- if (rootTag != null) {
- node.setTag(rootTag);
- }
- return constructDocument(node);
- }
-
- /**
- * Ensure that the stream contains a single document and construct it
- *
- * @param type the class of the instance being created
- * @return constructed instance
- * @throws ComposerException in case there are more documents in the stream
- */
- public Object getSingleData(Class<?> type) {
- // Ensure that the stream contains a single document and construct it
- final Node node = composer.getSingleNode();
- if (node != null && !Tag.NULL.equals(node.getTag())) {
- if (Object.class != type) {
- node.setTag(new Tag(type));
- } else if (rootTag != null) {
- node.setTag(rootTag);
- }
- return constructDocument(node);
- } else {
- Construct construct = yamlConstructors.get(Tag.NULL);
- return construct.construct(node);
- }
- }
-
- /**
- * Construct complete YAML document. Call the second step in case of
- * recursive structures. At the end cleans all the state.
- *
- * @param node root Node
- * @return Java instance
- */
- protected final Object constructDocument(Node node) {
- try {
- Object data = constructObject(node);
- fillRecursive();
- return data;
- } catch (RuntimeException e) {
- if (wrappedToRootException && !(e instanceof YAMLException)) {
- throw new YAMLException(e);
- } else {
- throw e;
- }
- } finally {
- //clean up resources
- constructedObjects.clear();
- recursiveObjects.clear();
- }
- }
-
- /**
- * Fill the recursive structures and clean the internal collections
- */
- private void fillRecursive() {
- if (!maps2fill.isEmpty()) {
- for (RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>> entry : maps2fill) {
- RecursiveTuple<Object, Object> key_value = entry._2();
- entry._1().put(key_value._1(), key_value._2());
- }
- maps2fill.clear();
- }
- if (!sets2fill.isEmpty()) {
- for (RecursiveTuple<Set<Object>, Object> value : sets2fill) {
- value._1().add(value._2());
- }
- sets2fill.clear();
- }
- }
-
- /**
- * Construct object from the specified Node. Return existing instance if the
- * node is already constructed.
- *
- * @param node Node to be constructed
- * @return Java instance
- */
- protected Object constructObject(Node node) {
+ /**
+ * It maps the node kind to the the Construct implementation. When the
+ * runtime class is known then the implicit tag is ignored.
+ */
+ protected final Map<NodeId, Construct> yamlClassConstructors = new EnumMap<NodeId, Construct>(
+ NodeId.class);
+ /**
+ * It maps the (explicit or implicit) tag to the Construct implementation.
+ * It is used:
+ * 1) explicit tag - if present.
+ * 2) implicit tag - when the runtime class of the instance is unknown (the
+ * node has the Object.class)
+ */
+ protected final Map<Tag, Construct> yamlConstructors = new HashMap<Tag, Construct>();
+ /**
+ * It maps the (explicit or implicit) tag to the Construct implementation.
+ * It is used when no exact match found.
+ */
+ protected final Map<String, Construct> yamlMultiConstructors = new HashMap<String, Construct>();
+
+ protected Composer composer;
+ final Map<Node, Object> constructedObjects;
+ private final Set<Node> recursiveObjects;
+ private final ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>> maps2fill;
+ private final ArrayList<RecursiveTuple<Set<Object>, Object>> sets2fill;
+
+ protected Tag rootTag;
+ private PropertyUtils propertyUtils;
+ private boolean explicitPropertyUtils;
+ private boolean allowDuplicateKeys = true;
+ private boolean wrappedToRootException = false;
+
+ private boolean enumCaseSensitive = false;
+
+ protected final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
+ protected final Map<Tag, Class<? extends Object>> typeTags;
+
+ protected LoaderOptions loadingConfig;
+
+ public BaseConstructor() {
+ this(new LoaderOptions());
+ }
+
+ public BaseConstructor(LoaderOptions loadingConfig) {
+ constructedObjects = new HashMap<Node, Object>();
+ recursiveObjects = new HashSet<Node>();
+ maps2fill = new ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>>();
+ sets2fill = new ArrayList<RecursiveTuple<Set<Object>, Object>>();
+ typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
+ typeTags = new HashMap<Tag, Class<? extends Object>>();
+
+ rootTag = null;
+ explicitPropertyUtils = false;
+
+ typeDefinitions.put(SortedMap.class, new TypeDescription(SortedMap.class, Tag.OMAP,
+ TreeMap.class));
+ typeDefinitions.put(SortedSet.class, new TypeDescription(SortedSet.class, Tag.SET,
+ TreeSet.class));
+ this.loadingConfig = loadingConfig;
+ }
+
+ public void setComposer(Composer composer) {
+ this.composer = composer;
+ }
+
+ /**
+ * Check if more documents available
+ *
+ * @return true when there are more YAML documents in the stream
+ */
+ public boolean checkData() {
+ // If there are more documents available?
+ return composer.checkNode();
+ }
+
+ /**
+ * Construct and return the next document
+ *
+ * @return constructed instance
+ */
+ public Object getData() throws NoSuchElementException {
+ // Construct and return the next document.
+ if (!composer.checkNode()) {
+ throw new NoSuchElementException("No document is available.");
+ }
+ Node node = composer.getNode();
+ if (rootTag != null) {
+ node.setTag(rootTag);
+ }
+ return constructDocument(node);
+ }
+
+ /**
+ * Ensure that the stream contains a single document and construct it
+ *
+ * @param type the class of the instance being created
+ * @return constructed instance
+ * @throws ComposerException in case there are more documents in the stream
+ */
+ public Object getSingleData(Class<?> type) {
+ // Ensure that the stream contains a single document and construct it
+ final Node node = composer.getSingleNode();
+ if (node != null && !Tag.NULL.equals(node.getTag())) {
+ if (Object.class != type) {
+ node.setTag(new Tag(type));
+ } else if (rootTag != null) {
+ node.setTag(rootTag);
+ }
+ return constructDocument(node);
+ } else {
+ Construct construct = yamlConstructors.get(Tag.NULL);
+ return construct.construct(node);
+ }
+ }
+
+ /**
+ * Construct complete YAML document. Call the second step in case of
+ * recursive structures. At the end cleans all the state.
+ *
+ * @param node root Node
+ * @return Java instance
+ */
+ protected final Object constructDocument(Node node) {
+ try {
+ Object data = constructObject(node);
+ fillRecursive();
+ return data;
+ } catch (RuntimeException e) {
+ if (wrappedToRootException && !(e instanceof YAMLException)) {
+ throw new YAMLException(e);
+ } else {
+ throw e;
+ }
+ } finally {
+ //clean up resources
+ constructedObjects.clear();
+ recursiveObjects.clear();
+ }
+ }
+
+ /**
+ * Fill the recursive structures and clean the internal collections
+ */
+ private void fillRecursive() {
+ if (!maps2fill.isEmpty()) {
+ for (RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>> entry : maps2fill) {
+ RecursiveTuple<Object, Object> key_value = entry._2();
+ entry._1().put(key_value._1(), key_value._2());
+ }
+ maps2fill.clear();
+ }
+ if (!sets2fill.isEmpty()) {
+ for (RecursiveTuple<Set<Object>, Object> value : sets2fill) {
+ value._1().add(value._2());
+ }
+ sets2fill.clear();
+ }
+ }
+
+ /**
+ * Construct object from the specified Node. Return existing instance if the
+ * node is already constructed.
+ *
+ * @param node Node to be constructed
+ * @return Java instance
+ */
+ protected Object constructObject(Node node) {
// System.out.println(" <<<< " + node.getAnchor() + " : " + node.getTag() + " : "
// + System.identityHashCode(node));
- if (constructedObjects.containsKey(node)) {
- return constructedObjects.get(node);
- }
- return constructObjectNoCheck(node);
- }
-
- protected Object constructObjectNoCheck(Node node) {
- recursiveObjects.add(node);
- Construct constructor = getConstructor(node);
- Object data = (constructedObjects.containsKey(node)) ? constructedObjects.get(node)
- : constructor.construct(node);
-
- finalizeConstruction(node, data);
- constructedObjects.put(node, data);
- if (node.isTwoStepsConstruction()) {
- constructor.construct2ndStep(node, data);
- }
- recursiveObjects.remove(node);
- return data;
- }
-
- /**
- * Get the constructor to construct the Node. For implicit tags if the
- * runtime class is known a dedicated Construct implementation is used.
- * Otherwise the constructor is chosen by the tag.
- *
- * @param node {@link Node} to construct an instance from
- * @return {@link Construct} implementation for the specified node
- */
- protected Construct getConstructor(Node node) {
- if (node.useClassConstructor()) {
- return yamlClassConstructors.get(node.getNodeId());
- } else {
- Construct constructor = yamlConstructors.get(node.getTag());
- if (constructor == null) {
- for (String prefix : yamlMultiConstructors.keySet()) {
- if (node.getTag().startsWith(prefix)) {
- return yamlMultiConstructors.get(prefix);
- }
- }
- return yamlConstructors.get(null);
- }
- return constructor;
- }
- }
-
- protected String constructScalar(ScalarNode node) {
- return node.getValue();
- }
-
- // >>>> DEFAULTS >>>>
- protected List<Object> createDefaultList(int initSize) {
- return new ArrayList<Object>(initSize);
- }
-
- protected Set<Object> createDefaultSet(int initSize) {
- return new LinkedHashSet<Object>(initSize);
- }
-
- protected Map<Object, Object> createDefaultMap(int initSize) {
- // respect order from YAML document
- return new LinkedHashMap<Object, Object>(initSize);
- }
-
- protected Object createArray(Class<?> type, int size) {
- return Array.newInstance(type.getComponentType(), size);
- }
-
- // <<<< DEFAULTS <<<<
-
- protected Object finalizeConstruction(Node node, Object data) {
- final Class<? extends Object> type = node.getType();
- if (typeDefinitions.containsKey(type)) {
- return typeDefinitions.get(type).finalizeConstruction(data);
- }
- return data;
- }
-
- // >>>> NEW instance
- protected Object newInstance(Node node) {
- try {
- return newInstance(Object.class, node);
- } catch (InstantiationException e) {
- throw new YAMLException(e);
- }
- }
-
- final protected Object newInstance(Class<?> ancestor, Node node) throws InstantiationException {
- return newInstance(ancestor, node, true);
- }
-
- protected Object newInstance(Class<?> ancestor, Node node, boolean tryDefault)
- throws InstantiationException {
- final Class<? extends Object> type = node.getType();
- if (typeDefinitions.containsKey(type)) {
- TypeDescription td = typeDefinitions.get(type);
- final Object instance = td.newInstance(node);
- if (instance != null) {
- return instance;
- }
- }
- if (tryDefault) {
- /*
- * Removed <code> have InstantiationException in case of abstract
- * type
- */
- if (ancestor.isAssignableFrom(type) && !Modifier.isAbstract(type.getModifiers())) {
- try {
- java.lang.reflect.Constructor<?> c = type.getDeclaredConstructor();
- c.setAccessible(true);
- return c.newInstance();
- } catch (NoSuchMethodException e) {
- throw new InstantiationException("NoSuchMethodException:"
- + e.getLocalizedMessage());
- } catch (Exception e) {
- throw new YAMLException(e);
- }
- }
- }
- throw new InstantiationException();
- }
-
- @SuppressWarnings("unchecked")
- protected Set<Object> newSet(CollectionNode<?> node) {
- try {
- return (Set<Object>) newInstance(Set.class, node);
- } catch (InstantiationException e) {
- return createDefaultSet(node.getValue().size());
- }
- }
-
- @SuppressWarnings("unchecked")
- protected List<Object> newList(SequenceNode node) {
- try {
- return (List<Object>) newInstance(List.class, node);
- } catch (InstantiationException e) {
- return createDefaultList(node.getValue().size());
+ if (constructedObjects.containsKey(node)) {
+ return constructedObjects.get(node);
+ }
+ return constructObjectNoCheck(node);
+ }
+
+ protected Object constructObjectNoCheck(Node node) {
+ recursiveObjects.add(node);
+ Construct constructor = getConstructor(node);
+ Object data = (constructedObjects.containsKey(node)) ? constructedObjects.get(node)
+ : constructor.construct(node);
+
+ finalizeConstruction(node, data);
+ constructedObjects.put(node, data);
+ if (node.isTwoStepsConstruction()) {
+ constructor.construct2ndStep(node, data);
+ }
+ recursiveObjects.remove(node);
+ return data;
+ }
+
+ /**
+ * Get the constructor to construct the Node. For implicit tags if the
+ * runtime class is known a dedicated Construct implementation is used.
+ * Otherwise the constructor is chosen by the tag.
+ *
+ * @param node {@link Node} to construct an instance from
+ * @return {@link Construct} implementation for the specified node
+ */
+ protected Construct getConstructor(Node node) {
+ if (node.useClassConstructor()) {
+ return yamlClassConstructors.get(node.getNodeId());
+ } else {
+ Construct constructor = yamlConstructors.get(node.getTag());
+ if (constructor == null) {
+ for (String prefix : yamlMultiConstructors.keySet()) {
+ if (node.getTag().startsWith(prefix)) {
+ return yamlMultiConstructors.get(prefix);
+ }
}
- }
-
- @SuppressWarnings("unchecked")
- protected Map<Object, Object> newMap(MappingNode node) {
+ return yamlConstructors.get(null);
+ }
+ return constructor;
+ }
+ }
+
+ protected String constructScalar(ScalarNode node) {
+ return node.getValue();
+ }
+
+ // >>>> DEFAULTS >>>>
+ protected List<Object> createDefaultList(int initSize) {
+ return new ArrayList<Object>(initSize);
+ }
+
+ protected Set<Object> createDefaultSet(int initSize) {
+ return new LinkedHashSet<Object>(initSize);
+ }
+
+ protected Map<Object, Object> createDefaultMap(int initSize) {
+ // respect order from YAML document
+ return new LinkedHashMap<Object, Object>(initSize);
+ }
+
+ protected Object createArray(Class<?> type, int size) {
+ return Array.newInstance(type.getComponentType(), size);
+ }
+
+ // <<<< DEFAULTS <<<<
+
+ protected Object finalizeConstruction(Node node, Object data) {
+ final Class<? extends Object> type = node.getType();
+ if (typeDefinitions.containsKey(type)) {
+ return typeDefinitions.get(type).finalizeConstruction(data);
+ }
+ return data;
+ }
+
+ // >>>> NEW instance
+ protected Object newInstance(Node node) {
+ try {
+ return newInstance(Object.class, node);
+ } catch (InstantiationException e) {
+ throw new YAMLException(e);
+ }
+ }
+
+ final protected Object newInstance(Class<?> ancestor, Node node) throws InstantiationException {
+ return newInstance(ancestor, node, true);
+ }
+
+ protected Object newInstance(Class<?> ancestor, Node node, boolean tryDefault)
+ throws InstantiationException {
+ final Class<? extends Object> type = node.getType();
+ if (typeDefinitions.containsKey(type)) {
+ TypeDescription td = typeDefinitions.get(type);
+ final Object instance = td.newInstance(node);
+ if (instance != null) {
+ return instance;
+ }
+ }
+ if (tryDefault) {
+ /*
+ * Removed <code> have InstantiationException in case of abstract
+ * type
+ */
+ if (ancestor.isAssignableFrom(type) && !Modifier.isAbstract(type.getModifiers())) {
try {
- return (Map<Object, Object>) newInstance(Map.class, node);
- } catch (InstantiationException e) {
- return createDefaultMap(node.getValue().size());
+ java.lang.reflect.Constructor<?> c = type.getDeclaredConstructor();
+ c.setAccessible(true);
+ return c.newInstance();
+ } catch (NoSuchMethodException e) {
+ throw new InstantiationException("NoSuchMethodException:"
+ + e.getLocalizedMessage());
+ } catch (Exception e) {
+ throw new YAMLException(e);
}
- }
-
- // <<<< NEW instance
-
- // >>>> Construct => NEW, 2ndStep(filling)
- protected List<? extends Object> constructSequence(SequenceNode node) {
- List<Object> result = newList(node);
- constructSequenceStep2(node, result);
- return result;
- }
-
- protected Set<? extends Object> constructSet(SequenceNode node) {
- Set<Object> result = newSet(node);
- constructSequenceStep2(node, result);
- return result;
- }
-
- protected Object constructArray(SequenceNode node) {
- return constructArrayStep2(node, createArray(node.getType(), node.getValue().size()));
- }
-
- protected void constructSequenceStep2(SequenceNode node, Collection<Object> collection) {
- for (Node child : node.getValue()) {
- collection.add(constructObject(child));
+ }
+ }
+ throw new InstantiationException();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Set<Object> newSet(CollectionNode<?> node) {
+ try {
+ return (Set<Object>) newInstance(Set.class, node);
+ } catch (InstantiationException e) {
+ return createDefaultSet(node.getValue().size());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected List<Object> newList(SequenceNode node) {
+ try {
+ return (List<Object>) newInstance(List.class, node);
+ } catch (InstantiationException e) {
+ return createDefaultList(node.getValue().size());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Map<Object, Object> newMap(MappingNode node) {
+ try {
+ return (Map<Object, Object>) newInstance(Map.class, node);
+ } catch (InstantiationException e) {
+ return createDefaultMap(node.getValue().size());
+ }
+ }
+
+ // <<<< NEW instance
+
+ // >>>> Construct => NEW, 2ndStep(filling)
+ protected List<? extends Object> constructSequence(SequenceNode node) {
+ List<Object> result = newList(node);
+ constructSequenceStep2(node, result);
+ return result;
+ }
+
+ protected Set<? extends Object> constructSet(SequenceNode node) {
+ Set<Object> result = newSet(node);
+ constructSequenceStep2(node, result);
+ return result;
+ }
+
+ protected Object constructArray(SequenceNode node) {
+ return constructArrayStep2(node, createArray(node.getType(), node.getValue().size()));
+ }
+
+ protected void constructSequenceStep2(SequenceNode node, Collection<Object> collection) {
+ for (Node child : node.getValue()) {
+ collection.add(constructObject(child));
+ }
+ }
+
+ protected Object constructArrayStep2(SequenceNode node, Object array) {
+ final Class<?> componentType = node.getType().getComponentType();
+
+ int index = 0;
+ for (Node child : node.getValue()) {
+ // Handle multi-dimensional arrays...
+ if (child.getType() == Object.class) {
+ child.setType(componentType);
+ }
+
+ final Object value = constructObject(child);
+
+ if (componentType.isPrimitive()) {
+ // Null values are disallowed for primitives
+ if (value == null) {
+ throw new NullPointerException(
+ "Unable to construct element value for " + child);
}
- }
-
- protected Object constructArrayStep2(SequenceNode node, Object array) {
- final Class<?> componentType = node.getType().getComponentType();
-
- int index = 0;
- for (Node child : node.getValue()) {
- // Handle multi-dimensional arrays...
- if (child.getType() == Object.class) {
- child.setType(componentType);
- }
-
- final Object value = constructObject(child);
- if (componentType.isPrimitive()) {
- // Null values are disallowed for primitives
- if (value == null) {
- throw new NullPointerException(
- "Unable to construct element value for " + child);
- }
+ // Primitive arrays require quite a lot of work.
+ if (byte.class.equals(componentType)) {
+ Array.setByte(array, index, ((Number) value).byteValue());
- // Primitive arrays require quite a lot of work.
- if (byte.class.equals(componentType)) {
- Array.setByte(array, index, ((Number) value).byteValue());
+ } else if (short.class.equals(componentType)) {
+ Array.setShort(array, index, ((Number) value).shortValue());
- } else if (short.class.equals(componentType)) {
- Array.setShort(array, index, ((Number) value).shortValue());
+ } else if (int.class.equals(componentType)) {
+ Array.setInt(array, index, ((Number) value).intValue());
- } else if (int.class.equals(componentType)) {
- Array.setInt(array, index, ((Number) value).intValue());
+ } else if (long.class.equals(componentType)) {
+ Array.setLong(array, index, ((Number) value).longValue());
- } else if (long.class.equals(componentType)) {
- Array.setLong(array, index, ((Number) value).longValue());
+ } else if (float.class.equals(componentType)) {
+ Array.setFloat(array, index, ((Number) value).floatValue());
- } else if (float.class.equals(componentType)) {
- Array.setFloat(array, index, ((Number) value).floatValue());
+ } else if (double.class.equals(componentType)) {
+ Array.setDouble(array, index, ((Number) value).doubleValue());
- } else if (double.class.equals(componentType)) {
- Array.setDouble(array, index, ((Number) value).doubleValue());
+ } else if (char.class.equals(componentType)) {
+ Array.setChar(array, index, ((Character) value).charValue());
- } else if (char.class.equals(componentType)) {
- Array.setChar(array, index, ((Character) value).charValue());
+ } else if (boolean.class.equals(componentType)) {
+ Array.setBoolean(array, index, ((Boolean) value).booleanValue());
- } else if (boolean.class.equals(componentType)) {
- Array.setBoolean(array, index, ((Boolean) value).booleanValue());
-
- } else {
- throw new YAMLException("unexpected primitive type");
- }
+ } else {
+ throw new YAMLException("unexpected primitive type");
+ }
- } else {
- // Non-primitive arrays can simply be assigned:
- Array.set(array, index, value);
- }
+ } else {
+ // Non-primitive arrays can simply be assigned:
+ Array.set(array, index, value);
+ }
- ++index;
- }
- return array;
+ ++index;
}
+ return array;
+ }
- protected Set<Object> constructSet(MappingNode node) {
- final Set<Object> set = newSet(node);
- constructSet2ndStep(node, set);
- return set;
- }
+ protected Set<Object> constructSet(MappingNode node) {
+ final Set<Object> set = newSet(node);
+ constructSet2ndStep(node, set);
+ return set;
+ }
- protected Map<Object, Object> constructMapping(MappingNode node) {
- final Map<Object, Object> mapping = newMap(node);
- constructMapping2ndStep(node, mapping);
- return mapping;
- }
+ protected Map<Object, Object> constructMapping(MappingNode node) {
+ final Map<Object, Object> mapping = newMap(node);
+ constructMapping2ndStep(node, mapping);
+ return mapping;
+ }
- protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
- List<NodeTuple> nodeValue = node.getValue();
- for (NodeTuple tuple : nodeValue) {
- Node keyNode = tuple.getKeyNode();
- Node valueNode = tuple.getValueNode();
+ protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
+ List<NodeTuple> nodeValue = node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ Node keyNode = tuple.getKeyNode();
+ Node valueNode = tuple.getValueNode();
// System.out.println(
// " >>>> " + keyNode.isTwoStepsConstruction() + " : " + keyNode.getStartMark());
- Object key = constructObject(keyNode);
- if (key != null) {
- try {
- key.hashCode();// check circular dependencies
- } catch (Exception e) {
- throw new ConstructorException("while constructing a mapping",
- node.getStartMark(), "found unacceptable key " + key,
- tuple.getKeyNode().getStartMark(), e);
- }
- }
- Object value = constructObject(valueNode);
- if (keyNode.isTwoStepsConstruction()) {
- if (loadingConfig.getAllowRecursiveKeys()) {
- postponeMapFilling(mapping, key, value);
- } else {
- throw new YAMLException("Recursive key for mapping is detected but it is not configured to be allowed.");
- }
- } else {
- mapping.put(key, value);
- }
- }
- }
-
- /*
- * if keyObject is created it 2 steps we should postpone putting
- * it in map because it may have different hash after
- * initialization compared to clean just created one. And map of
- * course does not observe key hashCode changes.
- */
- protected void postponeMapFilling(Map<Object, Object> mapping, Object key, Object value) {
- maps2fill.add(0, new RecursiveTuple(mapping, new RecursiveTuple(key, value)));
- }
-
- protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
- List<NodeTuple> nodeValue = node.getValue();
- for (NodeTuple tuple : nodeValue) {
- Node keyNode = tuple.getKeyNode();
- Object key = constructObject(keyNode);
- if (key != null) {
- try {
- key.hashCode();// check circular dependencies
- } catch (Exception e) {
- throw new ConstructorException("while constructing a Set", node.getStartMark(),
- "found unacceptable key " + key, tuple.getKeyNode().getStartMark(), e);
- }
- }
- if (keyNode.isTwoStepsConstruction()) {
- postponeSetFilling(set, key);
- } else {
- set.add(key);
- }
- }
- }
-
- /*
- * if keyObject is created it 2 steps we should postpone putting
- * it into the set because it may have different hash after
- * initialization compared to clean just created one. And set of
- * course does not observe value hashCode changes.
- */
- protected void postponeSetFilling(Set<Object> set, Object key) {
- sets2fill.add(0, new RecursiveTuple<Set<Object>, Object>(set, key));
- }
-
- public void setPropertyUtils(PropertyUtils propertyUtils) {
- this.propertyUtils = propertyUtils;
- explicitPropertyUtils = true;
- Collection<TypeDescription> tds = typeDefinitions.values();
- for (TypeDescription typeDescription : tds) {
- typeDescription.setPropertyUtils(propertyUtils);
- }
- }
-
- public final PropertyUtils getPropertyUtils() {
- if (propertyUtils == null) {
- propertyUtils = new PropertyUtils();
- }
- return propertyUtils;
- }
-
- /**
- * Make YAML aware how to parse a custom Class. If there is no root Class
- * assigned in constructor then the 'root' property of this definition is
- * respected.
- *
- * @param definition to be added to the Constructor
- * @return the previous value associated with <code>definition</code>, or
- * <code>null</code> if there was no mapping for <code>definition</code>.
- */
- public TypeDescription addTypeDescription(TypeDescription definition) {
- if (definition == null) {
- throw new NullPointerException("TypeDescription is required.");
- }
- Tag tag = definition.getTag();
- typeTags.put(tag, definition.getType());
- definition.setPropertyUtils(getPropertyUtils());
- return typeDefinitions.put(definition.getType(), definition);
- }
-
- private static class RecursiveTuple<T, K> {
- private final T _1;
- private final K _2;
-
- public RecursiveTuple(T _1, K _2) {
- this._1 = _1;
- this._2 = _2;
+ Object key = constructObject(keyNode);
+ if (key != null) {
+ try {
+ key.hashCode();// check circular dependencies
+ } catch (Exception e) {
+ throw new ConstructorException("while constructing a mapping",
+ node.getStartMark(), "found unacceptable key " + key,
+ tuple.getKeyNode().getStartMark(), e);
}
-
- public K _2() {
- return _2;
+ }
+ Object value = constructObject(valueNode);
+ if (keyNode.isTwoStepsConstruction()) {
+ if (loadingConfig.getAllowRecursiveKeys()) {
+ postponeMapFilling(mapping, key, value);
+ } else {
+ throw new YAMLException(
+ "Recursive key for mapping is detected but it is not configured to be allowed.");
}
-
- public T _1() {
- return _1;
+ } else {
+ mapping.put(key, value);
+ }
+ }
+ }
+
+ /*
+ * if keyObject is created it 2 steps we should postpone putting
+ * it in map because it may have different hash after
+ * initialization compared to clean just created one. And map of
+ * course does not observe key hashCode changes.
+ */
+ protected void postponeMapFilling(Map<Object, Object> mapping, Object key, Object value) {
+ maps2fill.add(0, new RecursiveTuple(mapping, new RecursiveTuple(key, value)));
+ }
+
+ protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
+ List<NodeTuple> nodeValue = node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ Node keyNode = tuple.getKeyNode();
+ Object key = constructObject(keyNode);
+ if (key != null) {
+ try {
+ key.hashCode();// check circular dependencies
+ } catch (Exception e) {
+ throw new ConstructorException("while constructing a Set", node.getStartMark(),
+ "found unacceptable key " + key, tuple.getKeyNode().getStartMark(), e);
}
- }
-
- public final boolean isExplicitPropertyUtils() {
- return explicitPropertyUtils;
- }
-
- public boolean isAllowDuplicateKeys() {
- return allowDuplicateKeys;
- }
-
- public void setAllowDuplicateKeys(boolean allowDuplicateKeys) {
- this.allowDuplicateKeys = allowDuplicateKeys;
- }
-
- public boolean isWrappedToRootException() {
- return wrappedToRootException;
- }
-
- public void setWrappedToRootException(boolean wrappedToRootException) {
- this.wrappedToRootException = wrappedToRootException;
- }
-
- public boolean isEnumCaseSensitive() {
- return enumCaseSensitive;
- }
-
- public void setEnumCaseSensitive(boolean enumCaseSensitive) {
- this.enumCaseSensitive = enumCaseSensitive;
- }
+ }
+ if (keyNode.isTwoStepsConstruction()) {
+ postponeSetFilling(set, key);
+ } else {
+ set.add(key);
+ }
+ }
+ }
+
+ /*
+ * if keyObject is created it 2 steps we should postpone putting
+ * it into the set because it may have different hash after
+ * initialization compared to clean just created one. And set of
+ * course does not observe value hashCode changes.
+ */
+ protected void postponeSetFilling(Set<Object> set, Object key) {
+ sets2fill.add(0, new RecursiveTuple<Set<Object>, Object>(set, key));
+ }
+
+ public void setPropertyUtils(PropertyUtils propertyUtils) {
+ this.propertyUtils = propertyUtils;
+ explicitPropertyUtils = true;
+ Collection<TypeDescription> tds = typeDefinitions.values();
+ for (TypeDescription typeDescription : tds) {
+ typeDescription.setPropertyUtils(propertyUtils);
+ }
+ }
+
+ public final PropertyUtils getPropertyUtils() {
+ if (propertyUtils == null) {
+ propertyUtils = new PropertyUtils();
+ }
+ return propertyUtils;
+ }
+
+ /**
+ * Make YAML aware how to parse a custom Class. If there is no root Class
+ * assigned in constructor then the 'root' property of this definition is
+ * respected.
+ *
+ * @param definition to be added to the Constructor
+ * @return the previous value associated with <code>definition</code>, or
+ * <code>null</code> if there was no mapping for <code>definition</code>.
+ */
+ public TypeDescription addTypeDescription(TypeDescription definition) {
+ if (definition == null) {
+ throw new NullPointerException("TypeDescription is required.");
+ }
+ Tag tag = definition.getTag();
+ typeTags.put(tag, definition.getType());
+ definition.setPropertyUtils(getPropertyUtils());
+ return typeDefinitions.put(definition.getType(), definition);
+ }
+
+ private static class RecursiveTuple<T, K> {
+
+ private final T _1;
+ private final K _2;
+
+ public RecursiveTuple(T _1, K _2) {
+ this._1 = _1;
+ this._2 = _2;
+ }
+
+ public K _2() {
+ return _2;
+ }
+
+ public T _1() {
+ return _1;
+ }
+ }
+
+ public final boolean isExplicitPropertyUtils() {
+ return explicitPropertyUtils;
+ }
+
+ public boolean isAllowDuplicateKeys() {
+ return allowDuplicateKeys;
+ }
+
+ public void setAllowDuplicateKeys(boolean allowDuplicateKeys) {
+ this.allowDuplicateKeys = allowDuplicateKeys;
+ }
+
+ public boolean isWrappedToRootException() {
+ return wrappedToRootException;
+ }
+
+ public void setWrappedToRootException(boolean wrappedToRootException) {
+ this.wrappedToRootException = wrappedToRootException;
+ }
+
+ public boolean isEnumCaseSensitive() {
+ return enumCaseSensitive;
+ }
+
+ public void setEnumCaseSensitive(boolean enumCaseSensitive) {
+ this.enumCaseSensitive = enumCaseSensitive;
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Construct.java b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
index 0fd46141..bf116520 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
@@ -21,30 +21,31 @@ import org.yaml.snakeyaml.nodes.Node;
* Provide a way to construct a Java instance out of the composed Node. Support
* recursive objects if it is required. (create Native Data Structure out of
* Node Graph)
- *
+ *
* @see <a href="http://yaml.org/spec/1.1/#id859109">Chapter 3. Processing YAML
* Information</a>
*/
public interface Construct {
- /**
- * Construct a Java instance with all the properties injected when it is
- * possible.
- *
- * @param node
- * composed Node
- * @return a complete Java instance
- */
- Object construct(Node node);
- /**
- * Apply the second step when constructing recursive structures. Because the
- * instance is already created it can assign a reference to itself.
- *
- * @param node
- * composed Node
- * @param object
- * the instance constructed earlier by
- * <code>construct(Node node)</code> for the provided Node
- */
- void construct2ndStep(Node node, Object object);
+ /**
+ * Construct a Java instance with all the properties injected when it is
+ * possible.
+ *
+ * @param node
+ * composed Node
+ * @return a complete Java instance
+ */
+ Object construct(Node node);
+
+ /**
+ * Apply the second step when constructing recursive structures. Because the
+ * instance is already created it can assign a reference to itself.
+ *
+ * @param node
+ * composed Node
+ * @param object
+ * the instance constructed earlier by
+ * <code>construct(Node node)</code> for the provided Node
+ */
+ void construct2ndStep(Node node, Object object);
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
index 7ef83854..48004fc2 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
@@ -25,7 +25,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.error.YAMLException;
@@ -44,640 +43,643 @@ import org.yaml.snakeyaml.util.EnumUtils;
*/
public class Constructor extends SafeConstructor {
- public Constructor() {
- this(Object.class);
+ public Constructor() {
+ this(Object.class);
+ }
+
+ public Constructor(LoaderOptions loadingConfig) {
+ this(Object.class, loadingConfig);
+ }
+
+ /**
+ * Create Constructor for the specified class as the root.
+ *
+ * @param theRoot
+ * - the class (usually JavaBean) to be constructed
+ */
+ public Constructor(Class<? extends Object> theRoot) {
+ this(new TypeDescription(checkRoot(theRoot)));
+ }
+
+ public Constructor(Class<? extends Object> theRoot, LoaderOptions loadingConfig) {
+ this(new TypeDescription(checkRoot(theRoot)), loadingConfig);
+ }
+
+ /**
+ * Ugly Java way to check the argument in the constructor
+ */
+ private static Class<? extends Object> checkRoot(Class<? extends Object> theRoot) {
+ if (theRoot == null) {
+ throw new NullPointerException("Root class must be provided.");
+ } else {
+ return theRoot;
+ }
+ }
+
+ public Constructor(TypeDescription theRoot) {
+ this(theRoot, null, new LoaderOptions());
+ }
+
+ public Constructor(TypeDescription theRoot, LoaderOptions loadingConfig) {
+ this(theRoot, null, loadingConfig);
+ }
+
+ public Constructor(TypeDescription theRoot, Collection<TypeDescription> moreTDs) {
+ this(theRoot, moreTDs, new LoaderOptions());
+ }
+
+ /**
+ * Create with all possible arguments
+ * @param theRoot - the class (usually JavaBean) to be constructed
+ * @param moreTDs - collection of classes used by the root class
+ * @param loadingConfig - configuration
+ */
+ public Constructor(TypeDescription theRoot, Collection<TypeDescription> moreTDs,
+ LoaderOptions loadingConfig) {
+ super(loadingConfig);
+ if (theRoot == null) {
+ throw new NullPointerException("Root type must be provided.");
}
-
- public Constructor(LoaderOptions loadingConfig) {
- this(Object.class, loadingConfig);
+ this.yamlConstructors.put(null, new ConstructYamlObject());
+ if (!Object.class.equals(theRoot.getType())) {
+ rootTag = new Tag(theRoot.getType());
}
-
- /**
- * Create Constructor for the specified class as the root.
- *
- * @param theRoot
- * - the class (usually JavaBean) to be constructed
- */
- public Constructor(Class<? extends Object> theRoot) {
- this(new TypeDescription(checkRoot(theRoot)));
+ yamlClassConstructors.put(NodeId.scalar, new ConstructScalar());
+ yamlClassConstructors.put(NodeId.mapping, new ConstructMapping());
+ yamlClassConstructors.put(NodeId.sequence, new ConstructSequence());
+ addTypeDescription(theRoot);
+ if (moreTDs != null) {
+ for (TypeDescription td : moreTDs) {
+ addTypeDescription(td);
+ }
}
-
- public Constructor(Class<? extends Object> theRoot, LoaderOptions loadingConfig) {
- this(new TypeDescription(checkRoot(theRoot)), loadingConfig);
+ }
+
+ /**
+ * Create Constructor for a class which does not have to be in the classpath
+ * or for a definition from a Spring ApplicationContext.
+ *
+ * @param theRoot
+ * fully qualified class name of the root class (usually
+ * JavaBean)
+ * @throws ClassNotFoundException if cannot be loaded by the classloader
+ */
+ public Constructor(String theRoot) throws ClassNotFoundException {
+ this(Class.forName(check(theRoot)));
+ }
+
+ public Constructor(String theRoot, LoaderOptions loadingConfig) throws ClassNotFoundException {
+ this(Class.forName(check(theRoot)), loadingConfig);
+ }
+
+ private static final String check(String s) {
+ if (s == null) {
+ throw new NullPointerException("Root type must be provided.");
}
+ if (s.trim().length() == 0) {
+ throw new YAMLException("Root type must be provided.");
+ }
+ return s;
+ }
+
+ /**
+ * Construct mapping instance (Map, JavaBean) when the runtime class is
+ * known.
+ */
+ protected class ConstructMapping implements Construct {
/**
- * Ugly Java way to check the argument in the constructor
+ * Construct JavaBean. If type safe collections are used please look at
+ * <code>TypeDescription</code>.
+ *
+ * @param node
+ * node where the keys are property names (they can only be
+ * <code>String</code>s) and values are objects to be created
+ * @return constructed JavaBean
*/
- private static Class<? extends Object> checkRoot(Class<? extends Object> theRoot) {
- if (theRoot == null) {
- throw new NullPointerException("Root class must be provided.");
- } else
- return theRoot;
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ if (Map.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ return newMap(mnode);
+ } else {
+ return constructMapping(mnode);
+ }
+ } else if (Collection.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ return newSet(mnode);
+ } else {
+ return constructSet(mnode);
+ }
+ } else {
+ Object obj = Constructor.this.newInstance(mnode);
+ if (node.isTwoStepsConstruction()) {
+ return obj;
+ } else {
+ return constructJavaBean2ndStep(mnode, obj);
+ }
+ }
}
- public Constructor(TypeDescription theRoot) {
- this(theRoot, null, new LoaderOptions());
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ if (Map.class.isAssignableFrom(node.getType())) {
+ constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
+ } else if (Set.class.isAssignableFrom(node.getType())) {
+ constructSet2ndStep((MappingNode) node, (Set<Object>) object);
+ } else {
+ constructJavaBean2ndStep((MappingNode) node, object);
+ }
}
- public Constructor(TypeDescription theRoot, LoaderOptions loadingConfig) {
- this(theRoot, null, loadingConfig);
+ // protected Object createEmptyJavaBean(MappingNode node) {
+ // try {
+ // Object instance = Constructor.this.newInstance(node);
+ // if (instance != null) {
+ // return instance;
+ // }
+ //
+ // /**
+ // * Using only default constructor. Everything else will be
+ // * initialized on 2nd step. If we do here some partial
+ // * initialization, how do we then track what need to be done on
+ // * 2nd step? I think it is better to get only object here (to
+ // * have it as reference for recursion) and do all other thing on
+ // * 2nd step.
+ // */
+ // java.lang.reflect.Constructor<?> c =
+ // node.getType().getDeclaredConstructor();
+ // c.setAccessible(true);
+ // return c.newInstance();
+ // } catch (Exception e) {
+ // throw new YAMLException(e);
+ // }
+ // }
+
+ protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
+ flattenMapping(node, true);
+ Class<? extends Object> beanType = node.getType();
+ List<NodeTuple> nodeValue = node.getValue();
+ for (NodeTuple tuple : nodeValue) {
+ Node valueNode = tuple.getValueNode();
+ // flattenMapping enforces keys to be Strings
+ String key = (String) constructObject(tuple.getKeyNode());
+ try {
+ TypeDescription memberDescription = typeDefinitions.get(beanType);
+ Property property = memberDescription == null ? getProperty(beanType, key)
+ : memberDescription.getProperty(key);
+
+ if (!property.isWritable()) {
+ throw new YAMLException("No writable property '" + key + "' on class: "
+ + beanType.getName());
+ }
+
+ valueNode.setType(property.getType());
+ final boolean typeDetected =
+ memberDescription != null && memberDescription.setupPropertyType(key, valueNode);
+ if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) {
+ // only if there is no explicit TypeDescription
+ Class<?>[] arguments = property.getActualTypeArguments();
+ if (arguments != null && arguments.length > 0) {
+ // type safe (generic) collection may contain the
+ // proper class
+ if (valueNode.getNodeId() == NodeId.sequence) {
+ Class<?> t = arguments[0];
+ SequenceNode snode = (SequenceNode) valueNode;
+ snode.setListType(t);
+ } else if (Map.class.isAssignableFrom(valueNode.getType())) {
+ Class<?> keyType = arguments[0];
+ Class<?> valueType = arguments[1];
+ MappingNode mnode = (MappingNode) valueNode;
+ mnode.setTypes(keyType, valueType);
+ mnode.setUseClassConstructor(true);
+ } else if (Collection.class.isAssignableFrom(valueNode.getType())) {
+ Class<?> t = arguments[0];
+ MappingNode mnode = (MappingNode) valueNode;
+ mnode.setOnlyKeyType(t);
+ mnode.setUseClassConstructor(true);
+ }
+ }
+ }
+
+ Object value = (memberDescription != null)
+ ? newInstance(memberDescription, key, valueNode)
+ : constructObject(valueNode);
+ // Correct when the property expects float but double was
+ // constructed
+ if (property.getType() == Float.TYPE || property.getType() == Float.class) {
+ if (value instanceof Double) {
+ value = ((Double) value).floatValue();
+ }
+ }
+ // Correct when the property a String but the value is binary
+ if (property.getType() == String.class && Tag.BINARY.equals(valueNode.getTag())
+ && value instanceof byte[]) {
+ value = new String((byte[]) value);
+ }
+
+ if (memberDescription == null
+ || !memberDescription.setProperty(object, key, value)) {
+ property.set(object, value);
+ }
+ } catch (DuplicateKeyException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ConstructorException(
+ "Cannot create property=" + key + " for JavaBean=" + object,
+ node.getStartMark(), e.getMessage(), valueNode.getStartMark(), e);
+ }
+ }
+ return object;
}
- public Constructor(TypeDescription theRoot, Collection<TypeDescription> moreTDs) {
- this(theRoot, moreTDs, new LoaderOptions());
+ private Object newInstance(TypeDescription memberDescription, String propertyName,
+ Node node) {
+ Object newInstance = memberDescription.newInstance(propertyName, node);
+ if (newInstance != null) {
+ constructedObjects.put(node, newInstance);
+ return
+ constructObjectNoCheck(node);
+ }
+ return constructObject(node);
}
- /**
- * Create with all possible arguments
- * @param theRoot - the class (usually JavaBean) to be constructed
- * @param moreTDs - collection of classes used by the root class
- * @param loadingConfig - configuration
- */
- public Constructor(TypeDescription theRoot, Collection<TypeDescription> moreTDs, LoaderOptions loadingConfig) {
- super(loadingConfig);
- if (theRoot == null) {
- throw new NullPointerException("Root type must be provided.");
- }
- this.yamlConstructors.put(null, new ConstructYamlObject());
- if (!Object.class.equals(theRoot.getType())) {
- rootTag = new Tag(theRoot.getType());
- }
- yamlClassConstructors.put(NodeId.scalar, new ConstructScalar());
- yamlClassConstructors.put(NodeId.mapping, new ConstructMapping());
- yamlClassConstructors.put(NodeId.sequence, new ConstructSequence());
- addTypeDescription(theRoot);
- if (moreTDs != null) {
- for (TypeDescription td : moreTDs) {
- addTypeDescription(td);
- }
- }
+ protected Property getProperty(Class<? extends Object> type, String name) {
+ return getPropertyUtils().getProperty(type, name);
}
-
- /**
- * Create Constructor for a class which does not have to be in the classpath
- * or for a definition from a Spring ApplicationContext.
- *
- * @param theRoot
- * fully qualified class name of the root class (usually
- * JavaBean)
- * @throws ClassNotFoundException if cannot be loaded by the classloader
- */
- public Constructor(String theRoot) throws ClassNotFoundException {
- this(Class.forName(check(theRoot)));
+ }
+
+ /**
+ * Construct an instance when the runtime class is not known but a global
+ * tag with a class name is defined. It delegates the construction to the
+ * appropriate constructor based on the node kind (scalar, sequence,
+ * mapping)
+ */
+ protected class ConstructYamlObject implements Construct {
+
+ private Construct getConstructor(Node node) {
+ Class<?> cl = getClassForNode(node);
+ node.setType(cl);
+ // call the constructor as if the runtime class is defined
+ Construct constructor = yamlClassConstructors.get(node.getNodeId());
+ return constructor;
}
- public Constructor(String theRoot, LoaderOptions loadingConfig) throws ClassNotFoundException {
- this(Class.forName(check(theRoot)), loadingConfig);
+ public Object construct(Node node) {
+ try {
+ return getConstructor(node).construct(node);
+ } catch (ConstructorException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ConstructorException(null, null, "Can't construct a java object for "
+ + node.getTag() + "; exception=" + e.getMessage(), node.getStartMark(), e);
+ }
}
- private static final String check(String s) {
- if (s == null) {
- throw new NullPointerException("Root type must be provided.");
+ public void construct2ndStep(Node node, Object object) {
+ try {
+ getConstructor(node).construct2ndStep(node, object);
+ } catch (Exception e) {
+ throw new ConstructorException(
+ null, null, "Can't construct a second step for a java object for "
+ + node.getTag() + "; exception=" + e.getMessage(),
+ node.getStartMark(), e);
+ }
+ }
+ }
+
+ /**
+ * Construct scalar instance when the runtime class is known. Recursive
+ * structures are not supported.
+ */
+ protected class ConstructScalar extends AbstractConstruct {
+
+ public Object construct(Node nnode) {
+ ScalarNode node = (ScalarNode) nnode;
+ Class<?> type = node.getType();
+
+ try {
+ return newInstance(type, node, false);
+ } catch (InstantiationException e1) {
+ }
+
+ Object result;
+ if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type)
+ || type == Boolean.class || Date.class.isAssignableFrom(type)
+ || type == Character.class || type == BigInteger.class
+ || type == BigDecimal.class || Enum.class.isAssignableFrom(type)
+ || Tag.BINARY.equals(node.getTag()) || Calendar.class.isAssignableFrom(type)
+ || type == UUID.class) {
+ // standard classes created directly
+ result = constructStandardJavaInstance(type, node);
+ } else {
+ // there must be only 1 constructor with 1 argument
+ java.lang.reflect.Constructor<?>[] javaConstructors = type
+ .getDeclaredConstructors();
+ int oneArgCount = 0;
+ java.lang.reflect.Constructor<?> javaConstructor = null;
+ for (java.lang.reflect.Constructor<?> c : javaConstructors) {
+ if (c.getParameterTypes().length == 1) {
+ oneArgCount++;
+ javaConstructor = c;
+ }
}
- if (s.trim().length() == 0) {
- throw new YAMLException("Root type must be provided.");
+ Object argument;
+ if (javaConstructor == null) {
+ try {
+ return newInstance(type, node, false);
+ } catch (InstantiationException ie) {
+ throw new YAMLException("No single argument constructor found for " + type
+ + " : " + ie.getMessage());
+ }
+ } else if (oneArgCount == 1) {
+ argument = constructStandardJavaInstance(javaConstructor.getParameterTypes()[0],
+ node);
+ } else {
+ // TODO it should be possible to use implicit types instead
+ // of forcing String. Resolver must be available here to
+ // obtain the implicit tag. Then we can set the tag and call
+ // callConstructor(node) to create the argument instance.
+ // On the other hand it may be safer to require a custom
+ // constructor to avoid guessing the argument class
+ argument = constructScalar(node);
+ try {
+ javaConstructor = type.getDeclaredConstructor(String.class);
+ } catch (Exception e) {
+ throw new YAMLException("Can't construct a java object for scalar "
+ + node.getTag() + "; No String constructor found. Exception="
+ + e.getMessage(), e);
+ }
}
- return s;
+ try {
+ javaConstructor.setAccessible(true);
+ result = javaConstructor.newInstance(argument);
+ } catch (Exception e) {
+ throw new ConstructorException(null, null,
+ "Can't construct a java object for scalar " + node.getTag()
+ + "; exception=" + e.getMessage(),
+ node.getStartMark(), e);
+ }
+ }
+ return result;
}
- /**
- * Construct mapping instance (Map, JavaBean) when the runtime class is
- * known.
- */
- protected class ConstructMapping implements Construct {
-
- /**
- * Construct JavaBean. If type safe collections are used please look at
- * <code>TypeDescription</code>.
- *
- * @param node
- * node where the keys are property names (they can only be
- * <code>String</code>s) and values are objects to be created
- * @return constructed JavaBean
- */
- public Object construct(Node node) {
- MappingNode mnode = (MappingNode) node;
- if (Map.class.isAssignableFrom(node.getType())) {
- if (node.isTwoStepsConstruction()) {
- return newMap(mnode);
- } else {
- return constructMapping(mnode);
- }
- } else if (Collection.class.isAssignableFrom(node.getType())) {
- if (node.isTwoStepsConstruction()) {
- return newSet(mnode);
- } else {
- return constructSet(mnode);
- }
- } else {
- Object obj = Constructor.this.newInstance(mnode);
- if (node.isTwoStepsConstruction()) {
- return obj;
- } else {
- return constructJavaBean2ndStep(mnode, obj);
- }
- }
+ @SuppressWarnings("unchecked")
+ private Object constructStandardJavaInstance(@SuppressWarnings("rawtypes") Class type,
+ ScalarNode node) {
+ Object result;
+ if (type == String.class) {
+ Construct stringConstructor = yamlConstructors.get(Tag.STR);
+ result = stringConstructor.construct(node);
+ } else if (type == Boolean.class || type == Boolean.TYPE) {
+ Construct boolConstructor = yamlConstructors.get(Tag.BOOL);
+ result = boolConstructor.construct(node);
+ } else if (type == Character.class || type == Character.TYPE) {
+ Construct charConstructor = yamlConstructors.get(Tag.STR);
+ String ch = (String) charConstructor.construct(node);
+ if (ch.length() == 0) {
+ result = null;
+ } else if (ch.length() != 1) {
+ throw new YAMLException(
+ "Invalid node Character: '" + ch + "'; length: " + ch.length());
+ } else {
+ result = Character.valueOf(ch.charAt(0));
}
-
- @SuppressWarnings("unchecked")
- public void construct2ndStep(Node node, Object object) {
- if (Map.class.isAssignableFrom(node.getType())) {
- constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
- } else if (Set.class.isAssignableFrom(node.getType())) {
- constructSet2ndStep((MappingNode) node, (Set<Object>) object);
- } else {
- constructJavaBean2ndStep((MappingNode) node, object);
- }
+ } else if (Date.class.isAssignableFrom(type)) {
+ Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
+ Date date = (Date) dateConstructor.construct(node);
+ if (type == Date.class) {
+ result = date;
+ } else {
+ try {
+ java.lang.reflect.Constructor<?> constr = type.getConstructor(long.class);
+ result = constr.newInstance(date.getTime());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new YAMLException("Cannot construct: '" + type + "'");
+ }
}
-
- // protected Object createEmptyJavaBean(MappingNode node) {
- // try {
- // Object instance = Constructor.this.newInstance(node);
- // if (instance != null) {
- // return instance;
- // }
- //
- // /**
- // * Using only default constructor. Everything else will be
- // * initialized on 2nd step. If we do here some partial
- // * initialization, how do we then track what need to be done on
- // * 2nd step? I think it is better to get only object here (to
- // * have it as reference for recursion) and do all other thing on
- // * 2nd step.
- // */
- // java.lang.reflect.Constructor<?> c =
- // node.getType().getDeclaredConstructor();
- // c.setAccessible(true);
- // return c.newInstance();
- // } catch (Exception e) {
- // throw new YAMLException(e);
- // }
- // }
-
- protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
- flattenMapping(node, true);
- Class<? extends Object> beanType = node.getType();
- List<NodeTuple> nodeValue = node.getValue();
- for (NodeTuple tuple : nodeValue) {
- Node valueNode = tuple.getValueNode();
- // flattenMapping enforces keys to be Strings
- String key = (String) constructObject(tuple.getKeyNode());
- try {
- TypeDescription memberDescription = typeDefinitions.get(beanType);
- Property property = memberDescription == null ? getProperty(beanType, key)
- : memberDescription.getProperty(key);
-
- if (!property.isWritable()) {
- throw new YAMLException("No writable property '" + key + "' on class: "
- + beanType.getName());
- }
-
- valueNode.setType(property.getType());
- final boolean typeDetected = (memberDescription != null)
- ? memberDescription.setupPropertyType(key, valueNode)
- : false;
- if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) {
- // only if there is no explicit TypeDescription
- Class<?>[] arguments = property.getActualTypeArguments();
- if (arguments != null && arguments.length > 0) {
- // type safe (generic) collection may contain the
- // proper class
- if (valueNode.getNodeId() == NodeId.sequence) {
- Class<?> t = arguments[0];
- SequenceNode snode = (SequenceNode) valueNode;
- snode.setListType(t);
- } else if (Map.class.isAssignableFrom(valueNode.getType())) {
- Class<?> keyType = arguments[0];
- Class<?> valueType = arguments[1];
- MappingNode mnode = (MappingNode) valueNode;
- mnode.setTypes(keyType, valueType);
- mnode.setUseClassConstructor(true);
- } else if (Collection.class.isAssignableFrom(valueNode.getType())) {
- Class<?> t = arguments[0];
- MappingNode mnode = (MappingNode) valueNode;
- mnode.setOnlyKeyType(t);
- mnode.setUseClassConstructor(true);
- }
- }
- }
-
- Object value = (memberDescription != null)
- ? newInstance(memberDescription, key, valueNode)
- : constructObject(valueNode);
- // Correct when the property expects float but double was
- // constructed
- if (property.getType() == Float.TYPE || property.getType() == Float.class) {
- if (value instanceof Double) {
- value = ((Double) value).floatValue();
- }
- }
- // Correct when the property a String but the value is binary
- if (property.getType() == String.class && Tag.BINARY.equals(valueNode.getTag())
- && value instanceof byte[]) {
- value = new String((byte[]) value);
- }
-
- if (memberDescription == null
- || !memberDescription.setProperty(object, key, value)) {
- property.set(object, value);
- }
- } catch (DuplicateKeyException e) {
- throw e;
- } catch (Exception e) {
- throw new ConstructorException(
- "Cannot create property=" + key + " for JavaBean=" + object,
- node.getStartMark(), e.getMessage(), valueNode.getStartMark(), e);
- }
- }
- return object;
+ } else if (type == Float.class || type == Double.class || type == Float.TYPE
+ || type == Double.TYPE || type == BigDecimal.class) {
+ if (type == BigDecimal.class) {
+ result = new BigDecimal(node.getValue());
+ } else {
+ Construct doubleConstructor = yamlConstructors.get(Tag.FLOAT);
+ result = doubleConstructor.construct(node);
+ if (type == Float.class || type == Float.TYPE) {
+ result = Float.valueOf(((Double) result).floatValue());
+ }
}
-
- private Object newInstance(TypeDescription memberDescription, String propertyName,
- Node node) {
- Object newInstance = memberDescription.newInstance(propertyName, node);
- if (newInstance != null) {
- constructedObjects.put(node, newInstance);
- return
- constructObjectNoCheck(node);
- }
- return constructObject(node);
+ } else if (type == Byte.class || type == Short.class || type == Integer.class
+ || type == Long.class || type == BigInteger.class || type == Byte.TYPE
+ || type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) {
+ Construct intConstructor = yamlConstructors.get(Tag.INT);
+ result = intConstructor.construct(node);
+ if (type == Byte.class || type == Byte.TYPE) {
+ result = Integer.valueOf(result.toString()).byteValue();
+ } else if (type == Short.class || type == Short.TYPE) {
+ result = Integer.valueOf(result.toString()).shortValue();
+ } else if (type == Integer.class || type == Integer.TYPE) {
+ result = Integer.parseInt(result.toString());
+ } else if (type == Long.class || type == Long.TYPE) {
+ result = Long.valueOf(result.toString());
+ } else {
+ // only BigInteger left
+ result = new BigInteger(result.toString());
}
-
- protected Property getProperty(Class<? extends Object> type, String name) {
- return getPropertyUtils().getProperty(type, name);
+ } else if (Enum.class.isAssignableFrom(type)) {
+ String enumValueName = node.getValue();
+ try {
+ if (loadingConfig.isEnumCaseSensitive()) {
+ result = Enum.valueOf(type, enumValueName);
+ } else {
+ result = EnumUtils.findEnumInsensitiveCase(type, enumValueName);
+ }
+ } catch (Exception ex) {
+ throw new YAMLException("Unable to find enum value '" + enumValueName
+ + "' for enum class: " + type.getName());
+ }
+ } else if (Calendar.class.isAssignableFrom(type)) {
+ ConstructYamlTimestamp contr = new ConstructYamlTimestamp();
+ contr.construct(node);
+ result = contr.getCalendar();
+ } else if (Number.class.isAssignableFrom(type)) {
+ //since we do not know the exact type we create Float
+ ConstructYamlFloat contr = new ConstructYamlFloat();
+ result = contr.construct(node);
+ } else if (UUID.class == type) {
+ result = UUID.fromString(node.getValue());
+ } else {
+ if (yamlConstructors.containsKey(node.getTag())) {
+ result = yamlConstructors.get(node.getTag()).construct(node);
+ } else {
+ throw new YAMLException("Unsupported class: " + type);
}
+ }
+ return result;
}
-
- /**
- * Construct an instance when the runtime class is not known but a global
- * tag with a class name is defined. It delegates the construction to the
- * appropriate constructor based on the node kind (scalar, sequence,
- * mapping)
- */
- protected class ConstructYamlObject implements Construct {
-
- private Construct getConstructor(Node node) {
- Class<?> cl = getClassForNode(node);
- node.setType(cl);
- // call the constructor as if the runtime class is defined
- Construct constructor = yamlClassConstructors.get(node.getNodeId());
- return constructor;
+ }
+
+ /**
+ * Construct sequence (List, Array, or immutable object) when the runtime
+ * class is known.
+ */
+ protected class ConstructSequence implements Construct {
+
+ @SuppressWarnings("unchecked")
+ public Object construct(Node node) {
+ SequenceNode snode = (SequenceNode) node;
+ if (Set.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ throw new YAMLException("Set cannot be recursive.");
+ } else {
+ return constructSet(snode);
}
-
- public Object construct(Node node) {
- try {
- return getConstructor(node).construct(node);
- } catch (ConstructorException e) {
- throw e;
- } catch (Exception e) {
- throw new ConstructorException(null, null, "Can't construct a java object for "
- + node.getTag() + "; exception=" + e.getMessage(), node.getStartMark(), e);
- }
+ } else if (Collection.class.isAssignableFrom(node.getType())) {
+ if (node.isTwoStepsConstruction()) {
+ return newList(snode);
+ } else {
+ return constructSequence(snode);
+ }
+ } else if (node.getType().isArray()) {
+ if (node.isTwoStepsConstruction()) {
+ return createArray(node.getType(), snode.getValue().size());
+ } else {
+ return constructArray(snode);
+ }
+ } else {
+ // create immutable object
+ List<java.lang.reflect.Constructor<?>> possibleConstructors = new ArrayList<java.lang.reflect.Constructor<?>>(
+ snode.getValue().size());
+ for (java.lang.reflect.Constructor<?> constructor : node.getType()
+ .getDeclaredConstructors()) {
+ if (snode.getValue().size() == constructor.getParameterTypes().length) {
+ possibleConstructors.add(constructor);
+ }
}
+ if (!possibleConstructors.isEmpty()) {
+ if (possibleConstructors.size() == 1) {
+ Object[] argumentList = new Object[snode.getValue().size()];
+ java.lang.reflect.Constructor<?> c = possibleConstructors.get(0);
+ int index = 0;
+ for (Node argumentNode : snode.getValue()) {
+ Class<?> type = c.getParameterTypes()[index];
+ // set runtime classes for arguments
+ argumentNode.setType(type);
+ argumentList[index++] = constructObject(argumentNode);
+ }
- public void construct2ndStep(Node node, Object object) {
try {
- getConstructor(node).construct2ndStep(node, object);
+ c.setAccessible(true);
+ return c.newInstance(argumentList);
} catch (Exception e) {
- throw new ConstructorException(
- null, null, "Can't construct a second step for a java object for "
- + node.getTag() + "; exception=" + e.getMessage(),
- node.getStartMark(), e);
+ throw new YAMLException(e);
}
- }
- }
-
- /**
- * Construct scalar instance when the runtime class is known. Recursive
- * structures are not supported.
- */
- protected class ConstructScalar extends AbstractConstruct {
- public Object construct(Node nnode) {
- ScalarNode node = (ScalarNode) nnode;
- Class<?> type = node.getType();
-
- try {
- return newInstance(type, node, false);
- } catch (InstantiationException e1) {
+ }
+
+ // use BaseConstructor
+ List<Object> argumentList = (List<Object>) constructSequence(snode);
+ Class<?>[] parameterTypes = new Class[argumentList.size()];
+ int index = 0;
+ for (Object parameter : argumentList) {
+ parameterTypes[index] = parameter.getClass();
+ index++;
+ }
+
+ for (java.lang.reflect.Constructor<?> c : possibleConstructors) {
+ Class<?>[] argTypes = c.getParameterTypes();
+ boolean foundConstructor = true;
+ for (int i = 0; i < argTypes.length; i++) {
+ if (!wrapIfPrimitive(argTypes[i]).isAssignableFrom(parameterTypes[i])) {
+ foundConstructor = false;
+ break;
+ }
}
-
- Object result;
- if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type)
- || type == Boolean.class || Date.class.isAssignableFrom(type)
- || type == Character.class || type == BigInteger.class
- || type == BigDecimal.class || Enum.class.isAssignableFrom(type)
- || Tag.BINARY.equals(node.getTag()) || Calendar.class.isAssignableFrom(type)
- || type == UUID.class) {
- // standard classes created directly
- result = constructStandardJavaInstance(type, node);
- } else {
- // there must be only 1 constructor with 1 argument
- java.lang.reflect.Constructor<?>[] javaConstructors = type
- .getDeclaredConstructors();
- int oneArgCount = 0;
- java.lang.reflect.Constructor<?> javaConstructor = null;
- for (java.lang.reflect.Constructor<?> c : javaConstructors) {
- if (c.getParameterTypes().length == 1) {
- oneArgCount++;
- javaConstructor = c;
- }
- }
- Object argument;
- if (javaConstructor == null) {
- try {
- return newInstance(type, node, false);
- } catch (InstantiationException ie) {
- throw new YAMLException("No single argument constructor found for " + type
- + " : " + ie.getMessage());
- }
- } else if (oneArgCount == 1) {
- argument = constructStandardJavaInstance(javaConstructor.getParameterTypes()[0],
- node);
- } else {
- // TODO it should be possible to use implicit types instead
- // of forcing String. Resolver must be available here to
- // obtain the implicit tag. Then we can set the tag and call
- // callConstructor(node) to create the argument instance.
- // On the other hand it may be safer to require a custom
- // constructor to avoid guessing the argument class
- argument = constructScalar(node);
- try {
- javaConstructor = type.getDeclaredConstructor(String.class);
- } catch (Exception e) {
- throw new YAMLException("Can't construct a java object for scalar "
- + node.getTag() + "; No String constructor found. Exception="
- + e.getMessage(), e);
- }
- }
- try {
- javaConstructor.setAccessible(true);
- result = javaConstructor.newInstance(argument);
- } catch (Exception e) {
- throw new ConstructorException(null, null,
- "Can't construct a java object for scalar " + node.getTag()
- + "; exception=" + e.getMessage(),
- node.getStartMark(), e);
- }
+ if (foundConstructor) {
+ try {
+ c.setAccessible(true);
+ return c.newInstance(argumentList.toArray());
+ } catch (Exception e) {
+ throw new YAMLException(e);
+ }
}
- return result;
+ }
}
+ throw new YAMLException(
+ "No suitable constructor with " + snode.getValue().size()
+ + " arguments found for " + node.getType());
- @SuppressWarnings("unchecked")
- private Object constructStandardJavaInstance(@SuppressWarnings("rawtypes") Class type,
- ScalarNode node) {
- Object result;
- if (type == String.class) {
- Construct stringConstructor = yamlConstructors.get(Tag.STR);
- result = stringConstructor.construct(node);
- } else if (type == Boolean.class || type == Boolean.TYPE) {
- Construct boolConstructor = yamlConstructors.get(Tag.BOOL);
- result = boolConstructor.construct(node);
- } else if (type == Character.class || type == Character.TYPE) {
- Construct charConstructor = yamlConstructors.get(Tag.STR);
- String ch = (String) charConstructor.construct(node);
- if (ch.length() == 0) {
- result = null;
- } else if (ch.length() != 1) {
- throw new YAMLException(
- "Invalid node Character: '" + ch + "'; length: " + ch.length());
- } else {
- result = Character.valueOf(ch.charAt(0));
- }
- } else if (Date.class.isAssignableFrom(type)) {
- Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
- Date date = (Date) dateConstructor.construct(node);
- if (type == Date.class) {
- result = date;
- } else {
- try {
- java.lang.reflect.Constructor<?> constr = type.getConstructor(long.class);
- result = constr.newInstance(date.getTime());
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new YAMLException("Cannot construct: '" + type + "'");
- }
- }
- } else if (type == Float.class || type == Double.class || type == Float.TYPE
- || type == Double.TYPE || type == BigDecimal.class) {
- if (type == BigDecimal.class) {
- result = new BigDecimal(node.getValue());
- } else {
- Construct doubleConstructor = yamlConstructors.get(Tag.FLOAT);
- result = doubleConstructor.construct(node);
- if (type == Float.class || type == Float.TYPE) {
- result = Float.valueOf(((Double) result).floatValue());
- }
- }
- } else if (type == Byte.class || type == Short.class || type == Integer.class
- || type == Long.class || type == BigInteger.class || type == Byte.TYPE
- || type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) {
- Construct intConstructor = yamlConstructors.get(Tag.INT);
- result = intConstructor.construct(node);
- if (type == Byte.class || type == Byte.TYPE) {
- result = Integer.valueOf(result.toString()).byteValue();
- } else if (type == Short.class || type == Short.TYPE) {
- result = Integer.valueOf(result.toString()).shortValue();
- } else if (type == Integer.class || type == Integer.TYPE) {
- result = Integer.parseInt(result.toString());
- } else if (type == Long.class || type == Long.TYPE) {
- result = Long.valueOf(result.toString());
- } else {
- // only BigInteger left
- result = new BigInteger(result.toString());
- }
- } else if (Enum.class.isAssignableFrom(type)) {
- String enumValueName = node.getValue();
- try {
- if(loadingConfig.isEnumCaseSensitive()) {
- result = Enum.valueOf(type, enumValueName);
- } else {
- result = EnumUtils.findEnumInsensitiveCase(type, enumValueName);
- }
- } catch (Exception ex) {
- throw new YAMLException("Unable to find enum value '" + enumValueName
- + "' for enum class: " + type.getName());
- }
- } else if (Calendar.class.isAssignableFrom(type)) {
- ConstructYamlTimestamp contr = new ConstructYamlTimestamp();
- contr.construct(node);
- result = contr.getCalendar();
- } else if (Number.class.isAssignableFrom(type)) {
- //since we do not know the exact type we create Float
- ConstructYamlFloat contr = new ConstructYamlFloat();
- result = contr.construct(node);
- } else if (UUID.class == type) {
- result = UUID.fromString(node.getValue());
- } else {
- if (yamlConstructors.containsKey(node.getTag())) {
- result = yamlConstructors.get(node.getTag()).construct(node);
- } else {
- throw new YAMLException("Unsupported class: " + type);
- }
- }
- return result;
- }
+ }
}
- /**
- * Construct sequence (List, Array, or immutable object) when the runtime
- * class is known.
- */
- protected class ConstructSequence implements Construct {
- @SuppressWarnings("unchecked")
- public Object construct(Node node) {
- SequenceNode snode = (SequenceNode) node;
- if (Set.class.isAssignableFrom(node.getType())) {
- if (node.isTwoStepsConstruction()) {
- throw new YAMLException("Set cannot be recursive.");
- } else {
- return constructSet(snode);
- }
- } else if (Collection.class.isAssignableFrom(node.getType())) {
- if (node.isTwoStepsConstruction()) {
- return newList(snode);
- } else {
- return constructSequence(snode);
- }
- } else if (node.getType().isArray()) {
- if (node.isTwoStepsConstruction()) {
- return createArray(node.getType(), snode.getValue().size());
- } else {
- return constructArray(snode);
- }
- } else {
- // create immutable object
- List<java.lang.reflect.Constructor<?>> possibleConstructors = new ArrayList<java.lang.reflect.Constructor<?>>(
- snode.getValue().size());
- for (java.lang.reflect.Constructor<?> constructor : node.getType()
- .getDeclaredConstructors()) {
- if (snode.getValue().size() == constructor.getParameterTypes().length) {
- possibleConstructors.add(constructor);
- }
- }
- if (!possibleConstructors.isEmpty()) {
- if (possibleConstructors.size() == 1) {
- Object[] argumentList = new Object[snode.getValue().size()];
- java.lang.reflect.Constructor<?> c = possibleConstructors.get(0);
- int index = 0;
- for (Node argumentNode : snode.getValue()) {
- Class<?> type = c.getParameterTypes()[index];
- // set runtime classes for arguments
- argumentNode.setType(type);
- argumentList[index++] = constructObject(argumentNode);
- }
-
- try {
- c.setAccessible(true);
- return c.newInstance(argumentList);
- } catch (Exception e) {
- throw new YAMLException(e);
- }
- }
-
- // use BaseConstructor
- List<Object> argumentList = (List<Object>) constructSequence(snode);
- Class<?>[] parameterTypes = new Class[argumentList.size()];
- int index = 0;
- for (Object parameter : argumentList) {
- parameterTypes[index] = parameter.getClass();
- index++;
- }
-
- for (java.lang.reflect.Constructor<?> c : possibleConstructors) {
- Class<?>[] argTypes = c.getParameterTypes();
- boolean foundConstructor = true;
- for (int i = 0; i < argTypes.length; i++) {
- if (!wrapIfPrimitive(argTypes[i]).isAssignableFrom(parameterTypes[i])) {
- foundConstructor = false;
- break;
- }
- }
- if (foundConstructor) {
- try {
- c.setAccessible(true);
- return c.newInstance(argumentList.toArray());
- } catch (Exception e) {
- throw new YAMLException(e);
- }
- }
- }
- }
- throw new YAMLException(
- "No suitable constructor with " + String.valueOf(snode.getValue().size())
- + " arguments found for " + node.getType());
-
- }
- }
-
- private final Class<? extends Object> wrapIfPrimitive(Class<?> clazz) {
- if (!clazz.isPrimitive()) {
- return clazz;
- }
- if (clazz == Integer.TYPE) {
- return Integer.class;
- }
- if (clazz == Float.TYPE) {
- return Float.class;
- }
- if (clazz == Double.TYPE) {
- return Double.class;
- }
- if (clazz == Boolean.TYPE) {
- return Boolean.class;
- }
- if (clazz == Long.TYPE) {
- return Long.class;
- }
- if (clazz == Character.TYPE) {
- return Character.class;
- }
- if (clazz == Short.TYPE) {
- return Short.class;
- }
- if (clazz == Byte.TYPE) {
- return Byte.class;
- }
- throw new YAMLException("Unexpected primitive " + clazz);
- }
-
- @SuppressWarnings("unchecked")
- public void construct2ndStep(Node node, Object object) {
- SequenceNode snode = (SequenceNode) node;
- if (List.class.isAssignableFrom(node.getType())) {
- List<Object> list = (List<Object>) object;
- constructSequenceStep2(snode, list);
- } else if (node.getType().isArray()) {
- constructArrayStep2(snode, object);
- } else {
- throw new YAMLException("Immutable objects cannot be recursive.");
- }
- }
+ private final Class<? extends Object> wrapIfPrimitive(Class<?> clazz) {
+ if (!clazz.isPrimitive()) {
+ return clazz;
+ }
+ if (clazz == Integer.TYPE) {
+ return Integer.class;
+ }
+ if (clazz == Float.TYPE) {
+ return Float.class;
+ }
+ if (clazz == Double.TYPE) {
+ return Double.class;
+ }
+ if (clazz == Boolean.TYPE) {
+ return Boolean.class;
+ }
+ if (clazz == Long.TYPE) {
+ return Long.class;
+ }
+ if (clazz == Character.TYPE) {
+ return Character.class;
+ }
+ if (clazz == Short.TYPE) {
+ return Short.class;
+ }
+ if (clazz == Byte.TYPE) {
+ return Byte.class;
+ }
+ throw new YAMLException("Unexpected primitive " + clazz);
}
- protected Class<?> getClassForNode(Node node) {
- Class<? extends Object> classForTag = typeTags.get(node.getTag());
- if (classForTag == null) {
- String name = node.getTag().getClassName();
- Class<?> cl;
- try {
- cl = getClassForName(name);
- } catch (ClassNotFoundException e) {
- throw new YAMLException("Class not found: " + name);
- }
- typeTags.put(node.getTag(), cl);
- return cl;
- } else {
- return classForTag;
- }
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ SequenceNode snode = (SequenceNode) node;
+ if (List.class.isAssignableFrom(node.getType())) {
+ List<Object> list = (List<Object>) object;
+ constructSequenceStep2(snode, list);
+ } else if (node.getType().isArray()) {
+ constructArrayStep2(snode, object);
+ } else {
+ throw new YAMLException("Immutable objects cannot be recursive.");
+ }
}
+ }
+
+ protected Class<?> getClassForNode(Node node) {
+ Class<? extends Object> classForTag = typeTags.get(node.getTag());
+ if (classForTag == null) {
+ String name = node.getTag().getClassName();
+ Class<?> cl;
+ try {
+ cl = getClassForName(name);
+ } catch (ClassNotFoundException e) {
+ throw new YAMLException("Class not found: " + name);
+ }
+ typeTags.put(node.getTag(), cl);
+ return cl;
+ } else {
+ return classForTag;
+ }
+ }
- protected Class<?> getClassForName(String name) throws ClassNotFoundException {
- try {
- return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
- } catch (ClassNotFoundException e) {
- return Class.forName(name);
- }
+ protected Class<?> getClassForName(String name) throws ClassNotFoundException {
+ try {
+ return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ return Class.forName(name);
}
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java
index 00929687..a619aff5 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/ConstructorException.java
@@ -19,15 +19,16 @@ import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.error.MarkedYAMLException;
public class ConstructorException extends MarkedYAMLException {
- private static final long serialVersionUID = -8816339931365239910L;
- protected ConstructorException(String context, Mark contextMark, String problem,
- Mark problemMark, Throwable cause) {
- super(context, contextMark, problem, problemMark, cause);
- }
+ private static final long serialVersionUID = -8816339931365239910L;
- protected ConstructorException(String context, Mark contextMark, String problem,
- Mark problemMark) {
- this(context, contextMark, problem, problemMark, null);
- }
+ protected ConstructorException(String context, Mark contextMark, String problem,
+ Mark problemMark, Throwable cause) {
+ super(context, contextMark, problem, problemMark, cause);
+ }
+
+ protected ConstructorException(String context, Mark contextMark, String problem,
+ Mark problemMark) {
+ this(context, contextMark, problem, problemMark, null);
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java
index 21af6bdd..2bfcd3e7 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/CustomClassLoaderConstructor.java
@@ -19,22 +19,23 @@ package org.yaml.snakeyaml.constructor;
* Construct instances with a custom Class Loader.
*/
public class CustomClassLoaderConstructor extends Constructor {
- private ClassLoader loader = CustomClassLoaderConstructor.class.getClassLoader();
- public CustomClassLoaderConstructor(ClassLoader cLoader) {
- this(Object.class, cLoader);
- }
+ private ClassLoader loader = CustomClassLoaderConstructor.class.getClassLoader();
- public CustomClassLoaderConstructor(Class<? extends Object> theRoot, ClassLoader theLoader) {
- super(theRoot);
- if (theLoader == null) {
- throw new NullPointerException("Loader must be provided.");
- }
- this.loader = theLoader;
- }
+ public CustomClassLoaderConstructor(ClassLoader cLoader) {
+ this(Object.class, cLoader);
+ }
- @Override
- protected Class<?> getClassForName(String name) throws ClassNotFoundException {
- return Class.forName(name, true, loader);
+ public CustomClassLoaderConstructor(Class<? extends Object> theRoot, ClassLoader theLoader) {
+ super(theRoot);
+ if (theLoader == null) {
+ throw new NullPointerException("Loader must be provided.");
}
+ this.loader = theLoader;
+ }
+
+ @Override
+ protected Class<?> getClassForName(String name) throws ClassNotFoundException {
+ return Class.forName(name, true, loader);
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/DuplicateKeyException.java b/src/main/java/org/yaml/snakeyaml/constructor/DuplicateKeyException.java
index dc7198ee..55654ef0 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/DuplicateKeyException.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/DuplicateKeyException.java
@@ -19,8 +19,9 @@ import org.yaml.snakeyaml.error.Mark;
public class DuplicateKeyException extends ConstructorException {
- protected DuplicateKeyException(Mark contextMark, Object key,
- Mark problemMark) {
- super("while constructing a mapping", contextMark, "found duplicate key " + String.valueOf(key), problemMark);
- }
+ protected DuplicateKeyException(Mark contextMark, Object key,
+ Mark problemMark) {
+ super("while constructing a mapping", contextMark, "found duplicate key " + key,
+ problemMark);
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
index 190d93ad..33ca27cd 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
@@ -28,7 +28,6 @@ import java.util.TimeZone;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
@@ -45,577 +44,596 @@ import org.yaml.snakeyaml.nodes.Tag;
*/
public class SafeConstructor extends BaseConstructor {
- public static final ConstructUndefined undefinedConstructor = new ConstructUndefined();
-
- public SafeConstructor() {
- this(new LoaderOptions());
- }
-
- public SafeConstructor(LoaderOptions loadingConfig) {
- super(loadingConfig);
- this.yamlConstructors.put(Tag.NULL, new ConstructYamlNull());
- this.yamlConstructors.put(Tag.BOOL, new ConstructYamlBool());
- this.yamlConstructors.put(Tag.INT, new ConstructYamlInt());
- this.yamlConstructors.put(Tag.FLOAT, new ConstructYamlFloat());
- this.yamlConstructors.put(Tag.BINARY, new ConstructYamlBinary());
- this.yamlConstructors.put(Tag.TIMESTAMP, new ConstructYamlTimestamp());
- this.yamlConstructors.put(Tag.OMAP, new ConstructYamlOmap());
- this.yamlConstructors.put(Tag.PAIRS, new ConstructYamlPairs());
- this.yamlConstructors.put(Tag.SET, new ConstructYamlSet());
- this.yamlConstructors.put(Tag.STR, new ConstructYamlStr());
- this.yamlConstructors.put(Tag.SEQ, new ConstructYamlSeq());
- this.yamlConstructors.put(Tag.MAP, new ConstructYamlMap());
- this.yamlConstructors.put(null, undefinedConstructor);
- this.yamlClassConstructors.put(NodeId.scalar, undefinedConstructor);
- this.yamlClassConstructors.put(NodeId.sequence, undefinedConstructor);
- this.yamlClassConstructors.put(NodeId.mapping, undefinedConstructor);
+ public static final ConstructUndefined undefinedConstructor = new ConstructUndefined();
+
+ public SafeConstructor() {
+ this(new LoaderOptions());
+ }
+
+ public SafeConstructor(LoaderOptions loadingConfig) {
+ super(loadingConfig);
+ this.yamlConstructors.put(Tag.NULL, new ConstructYamlNull());
+ this.yamlConstructors.put(Tag.BOOL, new ConstructYamlBool());
+ this.yamlConstructors.put(Tag.INT, new ConstructYamlInt());
+ this.yamlConstructors.put(Tag.FLOAT, new ConstructYamlFloat());
+ this.yamlConstructors.put(Tag.BINARY, new ConstructYamlBinary());
+ this.yamlConstructors.put(Tag.TIMESTAMP, new ConstructYamlTimestamp());
+ this.yamlConstructors.put(Tag.OMAP, new ConstructYamlOmap());
+ this.yamlConstructors.put(Tag.PAIRS, new ConstructYamlPairs());
+ this.yamlConstructors.put(Tag.SET, new ConstructYamlSet());
+ this.yamlConstructors.put(Tag.STR, new ConstructYamlStr());
+ this.yamlConstructors.put(Tag.SEQ, new ConstructYamlSeq());
+ this.yamlConstructors.put(Tag.MAP, new ConstructYamlMap());
+ this.yamlConstructors.put(null, undefinedConstructor);
+ this.yamlClassConstructors.put(NodeId.scalar, undefinedConstructor);
+ this.yamlClassConstructors.put(NodeId.sequence, undefinedConstructor);
+ this.yamlClassConstructors.put(NodeId.mapping, undefinedConstructor);
+ }
+
+ protected void flattenMapping(MappingNode node) {
+ flattenMapping(node, false);
+ }
+
+ protected void flattenMapping(MappingNode node, boolean forceStringKeys) {
+ // perform merging only on nodes containing merge node(s)
+ processDuplicateKeys(node, forceStringKeys);
+ if (node.isMerged()) {
+ node.setValue(mergeNode(node, true, new HashMap<Object, Integer>(),
+ new ArrayList<NodeTuple>(), forceStringKeys));
}
-
- protected void flattenMapping(MappingNode node) {
- flattenMapping(node, false);
- }
-
- protected void flattenMapping(MappingNode node, boolean forceStringKeys) {
- // perform merging only on nodes containing merge node(s)
- processDuplicateKeys(node, forceStringKeys);
- if (node.isMerged()) {
- node.setValue(mergeNode(node, true, new HashMap<Object, Integer>(),
- new ArrayList<NodeTuple>(), forceStringKeys));
+ }
+
+ protected void processDuplicateKeys(MappingNode node) {
+ processDuplicateKeys(node, false);
+ }
+
+ protected void processDuplicateKeys(MappingNode node, boolean forceStringKeys) {
+ List<NodeTuple> nodeValue = node.getValue();
+ Map<Object, Integer> keys = new HashMap<Object, Integer>(nodeValue.size());
+ TreeSet<Integer> toRemove = new TreeSet<Integer>();
+ int i = 0;
+ for (NodeTuple tuple : nodeValue) {
+ Node keyNode = tuple.getKeyNode();
+ if (!keyNode.getTag().equals(Tag.MERGE)) {
+ if (forceStringKeys) {
+ if (keyNode instanceof ScalarNode) {
+ keyNode.setType(String.class);
+ keyNode.setTag(Tag.STR);
+ } else {
+ throw new YAMLException(
+ "Keys must be scalars but found: " + keyNode);
+ }
}
- }
-
- protected void processDuplicateKeys(MappingNode node) {
- processDuplicateKeys(node, false);
- }
-
- protected void processDuplicateKeys(MappingNode node, boolean forceStringKeys) {
- List<NodeTuple> nodeValue = node.getValue();
- Map<Object, Integer> keys = new HashMap<Object, Integer>(nodeValue.size());
- TreeSet<Integer> toRemove = new TreeSet<Integer>();
- int i = 0;
- for (NodeTuple tuple : nodeValue) {
- Node keyNode = tuple.getKeyNode();
- if (!keyNode.getTag().equals(Tag.MERGE)) {
- if (forceStringKeys) {
- if (keyNode instanceof ScalarNode) {
- keyNode.setType(String.class);
- keyNode.setTag(Tag.STR);
- } else {
- throw new YAMLException(
- "Keys must be scalars but found: " + keyNode);
- }
- }
- Object key = constructObject(keyNode);
- if (key != null && !forceStringKeys) {
- if (keyNode.isTwoStepsConstruction()) {
- if(!loadingConfig.getAllowRecursiveKeys()) {
- throw new YAMLException(
- "Recursive key is detected but it is not configured to be allowed.");
- } else {
- try {
- key.hashCode();// check circular dependencies
- } catch (Exception e) {
- throw new ConstructorException("while constructing a mapping",
- node.getStartMark(), "found unacceptable key " + key,
- tuple.getKeyNode().getStartMark(), e);
- }
- }
- }
- }
-
- Integer prevIndex = keys.put(key, i);
- if (prevIndex != null) {
- if (!isAllowDuplicateKeys()) {
- throw new DuplicateKeyException(node.getStartMark(), key,
- tuple.getKeyNode().getStartMark());
- }
- toRemove.add(prevIndex);
- }
+ Object key = constructObject(keyNode);
+ if (key != null && !forceStringKeys) {
+ if (keyNode.isTwoStepsConstruction()) {
+ if (!loadingConfig.getAllowRecursiveKeys()) {
+ throw new YAMLException(
+ "Recursive key is detected but it is not configured to be allowed.");
+ } else {
+ try {
+ key.hashCode();// check circular dependencies
+ } catch (Exception e) {
+ throw new ConstructorException("while constructing a mapping",
+ node.getStartMark(), "found unacceptable key " + key,
+ tuple.getKeyNode().getStartMark(), e);
+ }
}
- i = i + 1;
+ }
}
- Iterator<Integer> indices2remove = toRemove.descendingIterator();
- while (indices2remove.hasNext()) {
- nodeValue.remove(indices2remove.next().intValue());
+ Integer prevIndex = keys.put(key, i);
+ if (prevIndex != null) {
+ if (!isAllowDuplicateKeys()) {
+ throw new DuplicateKeyException(node.getStartMark(), key,
+ tuple.getKeyNode().getStartMark());
+ }
+ toRemove.add(prevIndex);
}
+ }
+ i = i + 1;
}
- /**
- * Does merge for supplied mapping node.
- *
- * @param node
- * where to merge
- * @param isPreffered
- * true if keys of node should take precedence over others...
- * @param key2index
- * maps already merged keys to index from values
- * @param values
- * collects merged NodeTuple
- * @return list of the merged NodeTuple (to be set as value for the
- * MappingNode)
- */
- private List<NodeTuple> mergeNode(MappingNode node, boolean isPreffered,
- Map<Object, Integer> key2index, List<NodeTuple> values, boolean forceStringKeys) {
- Iterator<NodeTuple> iter = node.getValue().iterator();
- while (iter.hasNext()) {
- final NodeTuple nodeTuple = iter.next();
- final Node keyNode = nodeTuple.getKeyNode();
- final Node valueNode = nodeTuple.getValueNode();
- if (keyNode.getTag().equals(Tag.MERGE)) {
- iter.remove();
- switch (valueNode.getNodeId()) {
- case mapping:
- MappingNode mn = (MappingNode) valueNode;
- mergeNode(mn, false, key2index, values, forceStringKeys);
- break;
- case sequence:
- SequenceNode sn = (SequenceNode) valueNode;
- List<Node> vals = sn.getValue();
- for (Node subnode : vals) {
- if (!(subnode instanceof MappingNode)) {
- throw new ConstructorException("while constructing a mapping",
- node.getStartMark(),
- "expected a mapping for merging, but found "
- + subnode.getNodeId(),
- subnode.getStartMark());
- }
- MappingNode mnode = (MappingNode) subnode;
- mergeNode(mnode, false, key2index, values,forceStringKeys);
- }
- break;
- default:
- throw new ConstructorException("while constructing a mapping",
- node.getStartMark(),
- "expected a mapping or list of mappings for merging, but found "
- + valueNode.getNodeId(),
- valueNode.getStartMark());
- }
- } else {
- // we need to construct keys to avoid duplications
- if (forceStringKeys) {
- if (keyNode instanceof ScalarNode) {
- keyNode.setType(String.class);
- keyNode.setTag(Tag.STR);
- } else {
- throw new YAMLException("Keys must be scalars but found: " + keyNode);
- }
- }
- Object key = constructObject(keyNode);
- if (!key2index.containsKey(key)) { // 1st time merging key
- values.add(nodeTuple);
- // keep track where tuple for the key is
- key2index.put(key, values.size() - 1);
- } else if (isPreffered) { // there is value for the key, but we
- // need to override it
- // change value for the key using saved position
- values.set(key2index.get(key), nodeTuple);
- }
+ Iterator<Integer> indices2remove = toRemove.descendingIterator();
+ while (indices2remove.hasNext()) {
+ nodeValue.remove(indices2remove.next().intValue());
+ }
+ }
+
+ /**
+ * Does merge for supplied mapping node.
+ *
+ * @param node
+ * where to merge
+ * @param isPreffered
+ * true if keys of node should take precedence over others...
+ * @param key2index
+ * maps already merged keys to index from values
+ * @param values
+ * collects merged NodeTuple
+ * @return list of the merged NodeTuple (to be set as value for the
+ * MappingNode)
+ */
+ private List<NodeTuple> mergeNode(MappingNode node, boolean isPreffered,
+ Map<Object, Integer> key2index, List<NodeTuple> values, boolean forceStringKeys) {
+ Iterator<NodeTuple> iter = node.getValue().iterator();
+ while (iter.hasNext()) {
+ final NodeTuple nodeTuple = iter.next();
+ final Node keyNode = nodeTuple.getKeyNode();
+ final Node valueNode = nodeTuple.getValueNode();
+ if (keyNode.getTag().equals(Tag.MERGE)) {
+ iter.remove();
+ switch (valueNode.getNodeId()) {
+ case mapping:
+ MappingNode mn = (MappingNode) valueNode;
+ mergeNode(mn, false, key2index, values, forceStringKeys);
+ break;
+ case sequence:
+ SequenceNode sn = (SequenceNode) valueNode;
+ List<Node> vals = sn.getValue();
+ for (Node subnode : vals) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructing a mapping",
+ node.getStartMark(),
+ "expected a mapping for merging, but found "
+ + subnode.getNodeId(),
+ subnode.getStartMark());
+ }
+ MappingNode mnode = (MappingNode) subnode;
+ mergeNode(mnode, false, key2index, values, forceStringKeys);
}
+ break;
+ default:
+ throw new ConstructorException("while constructing a mapping",
+ node.getStartMark(),
+ "expected a mapping or list of mappings for merging, but found "
+ + valueNode.getNodeId(),
+ valueNode.getStartMark());
+ }
+ } else {
+ // we need to construct keys to avoid duplications
+ if (forceStringKeys) {
+ if (keyNode instanceof ScalarNode) {
+ keyNode.setType(String.class);
+ keyNode.setTag(Tag.STR);
+ } else {
+ throw new YAMLException("Keys must be scalars but found: " + keyNode);
+ }
+ }
+ Object key = constructObject(keyNode);
+ if (!key2index.containsKey(key)) { // 1st time merging key
+ values.add(nodeTuple);
+ // keep track where tuple for the key is
+ key2index.put(key, values.size() - 1);
+ } else if (isPreffered) { // there is value for the key, but we
+ // need to override it
+ // change value for the key using saved position
+ values.set(key2index.get(key), nodeTuple);
}
- return values;
+ }
}
+ return values;
+ }
+
+ @Override
+ protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
+ flattenMapping(node);
+ super.constructMapping2ndStep(node, mapping);
+ }
+
+ @Override
+ protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
+ flattenMapping(node);
+ super.constructSet2ndStep(node, set);
+ }
+
+ public class ConstructYamlNull extends AbstractConstruct {
@Override
- protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
- flattenMapping(node);
- super.constructMapping2ndStep(node, mapping);
+ public Object construct(Node node) {
+ if (node != null) {
+ constructScalar((ScalarNode) node);
+ }
+ return null;
}
+ }
+
+ private final static Map<String, Boolean> BOOL_VALUES = new HashMap<String, Boolean>();
+
+ static {
+ BOOL_VALUES.put("yes", Boolean.TRUE);
+ BOOL_VALUES.put("no", Boolean.FALSE);
+ BOOL_VALUES.put("true", Boolean.TRUE);
+ BOOL_VALUES.put("false", Boolean.FALSE);
+ BOOL_VALUES.put("on", Boolean.TRUE);
+ BOOL_VALUES.put("off", Boolean.FALSE);
+ }
+
+ public class ConstructYamlBool extends AbstractConstruct {
@Override
- protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
- flattenMapping(node);
- super.constructSet2ndStep(node, set);
+ public Object construct(Node node) {
+ String val = constructScalar((ScalarNode) node);
+ return BOOL_VALUES.get(val.toLowerCase());
}
+ }
- public class ConstructYamlNull extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- if (node != null) constructScalar((ScalarNode) node);
- return null;
+ public class ConstructYamlInt extends AbstractConstruct {
+
+ @Override
+ public Object construct(Node node) {
+ String value = constructScalar((ScalarNode) node).replaceAll("_", "");
+ if (value.isEmpty()) {
+ throw new ConstructorException("while constructing an int",
+ node.getStartMark(), "found empty value",
+ node.getStartMark());
+ }
+ int sign = +1;
+ char first = value.charAt(0);
+ if (first == '-') {
+ sign = -1;
+ value = value.substring(1);
+ } else if (first == '+') {
+ value = value.substring(1);
+ }
+ int base = 10;
+ if ("0".equals(value)) {
+ return Integer.valueOf(0);
+ } else if (value.startsWith("0b")) {
+ value = value.substring(2);
+ base = 2;
+ } else if (value.startsWith("0x")) {
+ value = value.substring(2);
+ base = 16;
+ } else if (value.startsWith("0")) {
+ value = value.substring(1);
+ base = 8;
+ } else if (value.indexOf(':') != -1) {
+ String[] digits = value.split(":");
+ int bes = 1;
+ int val = 0;
+ for (int i = 0, j = digits.length; i < j; i++) {
+ val += Long.parseLong(digits[j - i - 1]) * bes;
+ bes *= 60;
}
+ return createNumber(sign, String.valueOf(val), 10);
+ } else {
+ return createNumber(sign, value, 10);
+ }
+ return createNumber(sign, value, base);
}
+ }
- private final static Map<String, Boolean> BOOL_VALUES = new HashMap<String, Boolean>();
- static {
- BOOL_VALUES.put("yes", Boolean.TRUE);
- BOOL_VALUES.put("no", Boolean.FALSE);
- BOOL_VALUES.put("true", Boolean.TRUE);
- BOOL_VALUES.put("false", Boolean.FALSE);
- BOOL_VALUES.put("on", Boolean.TRUE);
- BOOL_VALUES.put("off", Boolean.FALSE);
- }
+ private static final int[][] RADIX_MAX = new int[17][2];
- public class ConstructYamlBool extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- String val = (String) constructScalar((ScalarNode) node);
- return BOOL_VALUES.get(val.toLowerCase());
- }
+ static {
+ int[] radixList = new int[]{2, 8, 10, 16};
+ for (int radix : radixList) {
+ RADIX_MAX[radix] = new int[]{maxLen(Integer.MAX_VALUE, radix), maxLen(Long.MAX_VALUE, radix)};
}
+ }
- public class ConstructYamlInt extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- String value = constructScalar((ScalarNode) node).replaceAll("_", "");
- if (value.isEmpty()) {
- throw new ConstructorException("while constructing an int",
- node.getStartMark(), "found empty value",
- node.getStartMark());
- }
- int sign = +1;
- char first = value.charAt(0);
- if (first == '-') {
- sign = -1;
- value = value.substring(1);
- } else if (first == '+') {
- value = value.substring(1);
- }
- int base = 10;
- if ("0".equals(value)) {
- return Integer.valueOf(0);
- } else if (value.startsWith("0b")) {
- value = value.substring(2);
- base = 2;
- } else if (value.startsWith("0x")) {
- value = value.substring(2);
- base = 16;
- } else if (value.startsWith("0")) {
- value = value.substring(1);
- base = 8;
- } else if (value.indexOf(':') != -1) {
- String[] digits = value.split(":");
- int bes = 1;
- int val = 0;
- for (int i = 0, j = digits.length; i < j; i++) {
- val += Long.parseLong(digits[j - i - 1]) * bes;
- bes *= 60;
- }
- return createNumber(sign, String.valueOf(val), 10);
- } else {
- return createNumber(sign, value, 10);
- }
- return createNumber(sign, value, base);
+ private static int maxLen(final int max, final int radix) {
+ return Integer.toString(max, radix).length();
+ }
+
+ private static int maxLen(final long max, final int radix) {
+ return Long.toString(max, radix).length();
+ }
+
+ private Number createNumber(int sign, String number, int radix) {
+ final int len = number != null ? number.length() : 0;
+ if (sign < 0) {
+ number = "-" + number;
+ }
+ final int[] maxArr = radix < RADIX_MAX.length ? RADIX_MAX[radix] : null;
+ if (maxArr != null) {
+ final boolean gtInt = len > maxArr[0];
+ if (gtInt) {
+ if (len > maxArr[1]) {
+ return new BigInteger(number, radix);
}
+ return createLongOrBigInteger(number, radix);
+ }
+ }
+ Number result;
+ try {
+ result = Integer.valueOf(number, radix);
+ } catch (NumberFormatException e) {
+ result = createLongOrBigInteger(number, radix);
+ }
+ return result;
+ }
+
+ protected static Number createLongOrBigInteger(final String number, final int radix) {
+ try {
+ return Long.valueOf(number, radix);
+ } catch (NumberFormatException e1) {
+ return new BigInteger(number, radix);
}
+ }
- private static final int[][] RADIX_MAX = new int[17][2];
- static {
- int[] radixList = new int[] {2, 8, 10, 16};
- for( int radix : radixList) {
- RADIX_MAX[radix] = new int[] { maxLen(Integer.MAX_VALUE,radix), maxLen(Long.MAX_VALUE,radix)};
+ public class ConstructYamlFloat extends AbstractConstruct {
+
+ @Override
+ public Object construct(Node node) {
+ String value = constructScalar((ScalarNode) node).replaceAll("_", "");
+ if (value.isEmpty()) {
+ throw new ConstructorException("while constructing a float",
+ node.getStartMark(), "found empty value",
+ node.getStartMark());
+ }
+ int sign = +1;
+ char first = value.charAt(0);
+ if (first == '-') {
+ sign = -1;
+ value = value.substring(1);
+ } else if (first == '+') {
+ value = value.substring(1);
+ }
+ String valLower = value.toLowerCase();
+ if (".inf".equals(valLower)) {
+ return Double
+ .valueOf(sign == -1 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ } else if (".nan".equals(valLower)) {
+ return Double.valueOf(Double.NaN);
+ } else if (value.indexOf(':') != -1) {
+ String[] digits = value.split(":");
+ int bes = 1;
+ double val = 0.0;
+ for (int i = 0, j = digits.length; i < j; i++) {
+ val += Double.parseDouble(digits[j - i - 1]) * bes;
+ bes *= 60;
}
+ return Double.valueOf(sign * val);
+ } else {
+ Double d = Double.valueOf(value);
+ return Double.valueOf(d.doubleValue() * sign);
+ }
}
+ }
+
+ public class ConstructYamlBinary extends AbstractConstruct {
- private static int maxLen(final int max, final int radix) {
- return Integer.toString(max,radix).length();
+ @Override
+ public Object construct(Node node) {
+ // Ignore white spaces for base64 encoded scalar
+ String noWhiteSpaces = constructScalar((ScalarNode) node).replaceAll("\\s",
+ "");
+ byte[] decoded = Base64Coder.decode(noWhiteSpaces.toCharArray());
+ return decoded;
}
- private static int maxLen(final long max,final int radix) {
- return Long.toString(max,radix).length();
+ }
+
+ private final static Pattern TIMESTAMP_REGEXP = Pattern.compile(
+ "^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$");
+ private final static Pattern YMD_REGEXP = Pattern
+ .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");
+
+ public static class ConstructYamlTimestamp extends AbstractConstruct {
+
+ private Calendar calendar;
+
+ public Calendar getCalendar() {
+ return calendar;
}
- private Number createNumber(int sign, String number, int radix) {
- final int len = number != null ? number.length() : 0;
- if (sign < 0) {
- number = "-" + number;
+
+ @Override
+ public Object construct(Node node) {
+ ScalarNode scalar = (ScalarNode) node;
+ String nodeValue = scalar.getValue();
+ Matcher match = YMD_REGEXP.matcher(nodeValue);
+ if (match.matches()) {
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.clear();
+ calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1); // x
+ calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ return calendar.getTime();
+ } else {
+ match = TIMESTAMP_REGEXP.matcher(nodeValue);
+ if (!match.matches()) {
+ throw new YAMLException("Unexpected timestamp: " + nodeValue);
}
- final int[] maxArr = radix < RADIX_MAX.length ? RADIX_MAX[radix] : null;
- if (maxArr != null) {
- final boolean gtInt = len >maxArr[0];
- if (gtInt) {
- if(len > maxArr[1]) {
- return new BigInteger(number, radix);
- }
- return createLongOrBigInteger(number, radix);
- }
+ String year_s = match.group(1);
+ String month_s = match.group(2);
+ String day_s = match.group(3);
+ String hour_s = match.group(4);
+ String min_s = match.group(5);
+ // seconds and milliseconds
+ String seconds = match.group(6);
+ String millis = match.group(7);
+ if (millis != null) {
+ seconds = seconds + "." + millis;
}
- Number result;
- try {
- result = Integer.valueOf(number, radix);
- } catch (NumberFormatException e) {
- result = createLongOrBigInteger(number, radix);
+ double fractions = Double.parseDouble(seconds);
+ int sec_s = (int) Math.round(Math.floor(fractions));
+ int usec = (int) Math.round((fractions - sec_s) * 1000);
+ // timezone
+ String timezoneh_s = match.group(8);
+ String timezonem_s = match.group(9);
+ TimeZone timeZone;
+ if (timezoneh_s != null) {
+ String time = timezonem_s != null ? ":" + timezonem_s : "00";
+ timeZone = TimeZone.getTimeZone("GMT" + timezoneh_s + time);
+ } else {
+ // no time zone provided
+ timeZone = TimeZone.getTimeZone("UTC");
}
- return result;
+ calendar = Calendar.getInstance(timeZone);
+ calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
+ // Java's months are zero-based...
+ calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1);
+ calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
+ calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour_s));
+ calendar.set(Calendar.MINUTE, Integer.parseInt(min_s));
+ calendar.set(Calendar.SECOND, sec_s);
+ calendar.set(Calendar.MILLISECOND, usec);
+ return calendar.getTime();
+ }
}
+ }
- protected static Number createLongOrBigInteger(final String number,final int radix) {
- try {
- return Long.valueOf(number, radix);
- } catch (NumberFormatException e1) {
- return new BigInteger(number, radix);
- }
- }
+ public class ConstructYamlOmap extends AbstractConstruct {
- public class ConstructYamlFloat extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- String value = constructScalar((ScalarNode) node).replaceAll("_", "");
- if (value.isEmpty()) {
- throw new ConstructorException("while constructing a float",
- node.getStartMark(), "found empty value",
- node.getStartMark());
- }
- int sign = +1;
- char first = value.charAt(0);
- if (first == '-') {
- sign = -1;
- value = value.substring(1);
- } else if (first == '+') {
- value = value.substring(1);
- }
- String valLower = value.toLowerCase();
- if (".inf".equals(valLower)) {
- return Double
- .valueOf(sign == -1 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
- } else if (".nan".equals(valLower)) {
- return Double.valueOf(Double.NaN);
- } else if (value.indexOf(':') != -1) {
- String[] digits = value.split(":");
- int bes = 1;
- double val = 0.0;
- for (int i = 0, j = digits.length; i < j; i++) {
- val += Double.parseDouble(digits[j - i - 1]) * bes;
- bes *= 60;
- }
- return Double.valueOf(sign * val);
- } else {
- Double d = Double.valueOf(value);
- return Double.valueOf(d.doubleValue() * sign);
- }
+ @Override
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ Map<Object, Object> omap = new LinkedHashMap<Object, Object>();
+ if (!(node instanceof SequenceNode)) {
+ throw new ConstructorException("while constructing an ordered map",
+ node.getStartMark(), "expected a sequence, but found " + node.getNodeId(),
+ node.getStartMark());
+ }
+ SequenceNode snode = (SequenceNode) node;
+ for (Node subnode : snode.getValue()) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructing an ordered map",
+ node.getStartMark(),
+ "expected a mapping of length 1, but found " + subnode.getNodeId(),
+ subnode.getStartMark());
}
- }
-
- public class ConstructYamlBinary extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- // Ignore white spaces for base64 encoded scalar
- String noWhiteSpaces = constructScalar((ScalarNode) node).toString().replaceAll("\\s",
- "");
- byte[] decoded = Base64Coder.decode(noWhiteSpaces.toCharArray());
- return decoded;
+ MappingNode mnode = (MappingNode) subnode;
+ if (mnode.getValue().size() != 1) {
+ throw new ConstructorException("while constructing an ordered map",
+ node.getStartMark(), "expected a single mapping item, but found "
+ + mnode.getValue().size() + " items",
+ mnode.getStartMark());
}
+ Node keyNode = mnode.getValue().get(0).getKeyNode();
+ Node valueNode = mnode.getValue().get(0).getValueNode();
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ omap.put(key, value);
+ }
+ return omap;
}
+ }
- private final static Pattern TIMESTAMP_REGEXP = Pattern.compile(
- "^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$");
- private final static Pattern YMD_REGEXP = Pattern
- .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");
-
- public static class ConstructYamlTimestamp extends AbstractConstruct {
- private Calendar calendar;
+ public class ConstructYamlPairs extends AbstractConstruct {
- public Calendar getCalendar() {
- return calendar;
+ @Override
+ public Object construct(Node node) {
+ // Note: we do not check for duplicate keys, because it's too
+ // CPU-expensive.
+ if (!(node instanceof SequenceNode)) {
+ throw new ConstructorException("while constructing pairs", node.getStartMark(),
+ "expected a sequence, but found " + node.getNodeId(), node.getStartMark());
+ }
+ SequenceNode snode = (SequenceNode) node;
+ List<Object[]> pairs = new ArrayList<Object[]>(snode.getValue().size());
+ for (Node subnode : snode.getValue()) {
+ if (!(subnode instanceof MappingNode)) {
+ throw new ConstructorException("while constructingpairs", node.getStartMark(),
+ "expected a mapping of length 1, but found " + subnode.getNodeId(),
+ subnode.getStartMark());
}
-
- @Override
- public Object construct(Node node) {
- ScalarNode scalar = (ScalarNode) node;
- String nodeValue = scalar.getValue();
- Matcher match = YMD_REGEXP.matcher(nodeValue);
- if (match.matches()) {
- String year_s = match.group(1);
- String month_s = match.group(2);
- String day_s = match.group(3);
- calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- calendar.clear();
- calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
- // Java's months are zero-based...
- calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1); // x
- calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
- return calendar.getTime();
- } else {
- match = TIMESTAMP_REGEXP.matcher(nodeValue);
- if (!match.matches()) {
- throw new YAMLException("Unexpected timestamp: " + nodeValue);
- }
- String year_s = match.group(1);
- String month_s = match.group(2);
- String day_s = match.group(3);
- String hour_s = match.group(4);
- String min_s = match.group(5);
- // seconds and milliseconds
- String seconds = match.group(6);
- String millis = match.group(7);
- if (millis != null) {
- seconds = seconds + "." + millis;
- }
- double fractions = Double.parseDouble(seconds);
- int sec_s = (int) Math.round(Math.floor(fractions));
- int usec = (int) Math.round((fractions - sec_s) * 1000);
- // timezone
- String timezoneh_s = match.group(8);
- String timezonem_s = match.group(9);
- TimeZone timeZone;
- if (timezoneh_s != null) {
- String time = timezonem_s != null ? ":" + timezonem_s : "00";
- timeZone = TimeZone.getTimeZone("GMT" + timezoneh_s + time);
- } else {
- // no time zone provided
- timeZone = TimeZone.getTimeZone("UTC");
- }
- calendar = Calendar.getInstance(timeZone);
- calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
- // Java's months are zero-based...
- calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1);
- calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
- calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour_s));
- calendar.set(Calendar.MINUTE, Integer.parseInt(min_s));
- calendar.set(Calendar.SECOND, sec_s);
- calendar.set(Calendar.MILLISECOND, usec);
- return calendar.getTime();
- }
+ MappingNode mnode = (MappingNode) subnode;
+ if (mnode.getValue().size() != 1) {
+ throw new ConstructorException("while constructing pairs", node.getStartMark(),
+ "expected a single mapping item, but found " + mnode.getValue().size()
+ + " items",
+ mnode.getStartMark());
}
+ Node keyNode = mnode.getValue().get(0).getKeyNode();
+ Node valueNode = mnode.getValue().get(0).getValueNode();
+ Object key = constructObject(keyNode);
+ Object value = constructObject(valueNode);
+ pairs.add(new Object[]{key, value});
+ }
+ return pairs;
}
+ }
- public class ConstructYamlOmap extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- // Note: we do not check for duplicate keys, because it's too
- // CPU-expensive.
- Map<Object, Object> omap = new LinkedHashMap<Object, Object>();
- if (!(node instanceof SequenceNode)) {
- throw new ConstructorException("while constructing an ordered map",
- node.getStartMark(), "expected a sequence, but found " + node.getNodeId(),
- node.getStartMark());
- }
- SequenceNode snode = (SequenceNode) node;
- for (Node subnode : snode.getValue()) {
- if (!(subnode instanceof MappingNode)) {
- throw new ConstructorException("while constructing an ordered map",
- node.getStartMark(),
- "expected a mapping of length 1, but found " + subnode.getNodeId(),
- subnode.getStartMark());
- }
- MappingNode mnode = (MappingNode) subnode;
- if (mnode.getValue().size() != 1) {
- throw new ConstructorException("while constructing an ordered map",
- node.getStartMark(), "expected a single mapping item, but found "
- + mnode.getValue().size() + " items",
- mnode.getStartMark());
- }
- Node keyNode = mnode.getValue().get(0).getKeyNode();
- Node valueNode = mnode.getValue().get(0).getValueNode();
- Object key = constructObject(keyNode);
- Object value = constructObject(valueNode);
- omap.put(key, value);
- }
- return omap;
- }
+ public class ConstructYamlSet implements Construct {
+
+ @Override
+ public Object construct(Node node) {
+ if (node.isTwoStepsConstruction()) {
+ return (constructedObjects.containsKey(node) ? constructedObjects.get(node)
+ : createDefaultSet(((MappingNode) node).getValue().size()));
+ } else {
+ return constructSet((MappingNode) node);
+ }
}
- public class ConstructYamlPairs extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- // Note: we do not check for duplicate keys, because it's too
- // CPU-expensive.
- if (!(node instanceof SequenceNode)) {
- throw new ConstructorException("while constructing pairs", node.getStartMark(),
- "expected a sequence, but found " + node.getNodeId(), node.getStartMark());
- }
- SequenceNode snode = (SequenceNode) node;
- List<Object[]> pairs = new ArrayList<Object[]>(snode.getValue().size());
- for (Node subnode : snode.getValue()) {
- if (!(subnode instanceof MappingNode)) {
- throw new ConstructorException("while constructingpairs", node.getStartMark(),
- "expected a mapping of length 1, but found " + subnode.getNodeId(),
- subnode.getStartMark());
- }
- MappingNode mnode = (MappingNode) subnode;
- if (mnode.getValue().size() != 1) {
- throw new ConstructorException("while constructing pairs", node.getStartMark(),
- "expected a single mapping item, but found " + mnode.getValue().size()
- + " items",
- mnode.getStartMark());
- }
- Node keyNode = mnode.getValue().get(0).getKeyNode();
- Node valueNode = mnode.getValue().get(0).getValueNode();
- Object key = constructObject(keyNode);
- Object value = constructObject(valueNode);
- pairs.add(new Object[] { key, value });
- }
- return pairs;
- }
+ @Override
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ if (node.isTwoStepsConstruction()) {
+ constructSet2ndStep((MappingNode) node, (Set<Object>) object);
+ } else {
+ throw new YAMLException("Unexpected recursive set structure. Node: " + node);
+ }
}
+ }
- public class ConstructYamlSet implements Construct {
- @Override
- public Object construct(Node node) {
- if (node.isTwoStepsConstruction()) {
- return (constructedObjects.containsKey(node) ? constructedObjects.get(node)
- : createDefaultSet(((MappingNode) node).getValue().size()));
- } else {
- return constructSet((MappingNode) node);
- }
- }
+ public class ConstructYamlStr extends AbstractConstruct {
- @Override
- @SuppressWarnings("unchecked")
- public void construct2ndStep(Node node, Object object) {
- if (node.isTwoStepsConstruction()) {
- constructSet2ndStep((MappingNode) node, (Set<Object>) object);
- } else {
- throw new YAMLException("Unexpected recursive set structure. Node: " + node);
- }
- }
+ @Override
+ public Object construct(Node node) {
+ return constructScalar((ScalarNode) node);
}
+ }
- public class ConstructYamlStr extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- return constructScalar((ScalarNode) node);
- }
- }
+ public class ConstructYamlSeq implements Construct {
- public class ConstructYamlSeq implements Construct {
- @Override
- public Object construct(Node node) {
- SequenceNode seqNode = (SequenceNode) node;
- if (node.isTwoStepsConstruction()) {
- return newList(seqNode);
- } else {
- return constructSequence(seqNode);
- }
- }
+ @Override
+ public Object construct(Node node) {
+ SequenceNode seqNode = (SequenceNode) node;
+ if (node.isTwoStepsConstruction()) {
+ return newList(seqNode);
+ } else {
+ return constructSequence(seqNode);
+ }
+ }
- @Override
- @SuppressWarnings("unchecked")
- public void construct2ndStep(Node node, Object data) {
- if (node.isTwoStepsConstruction()) {
- constructSequenceStep2((SequenceNode) node, (List<Object>) data);
- } else {
- throw new YAMLException("Unexpected recursive sequence structure. Node: " + node);
- }
- }
+ @Override
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object data) {
+ if (node.isTwoStepsConstruction()) {
+ constructSequenceStep2((SequenceNode) node, (List<Object>) data);
+ } else {
+ throw new YAMLException("Unexpected recursive sequence structure. Node: " + node);
+ }
}
+ }
- public class ConstructYamlMap implements Construct {
- @Override
- public Object construct(Node node) {
- MappingNode mnode = (MappingNode) node;
- if (node.isTwoStepsConstruction()) {
- return createDefaultMap(mnode.getValue().size());
- } else {
- return constructMapping(mnode);
- }
- }
+ public class ConstructYamlMap implements Construct {
- @Override
- @SuppressWarnings("unchecked")
- public void construct2ndStep(Node node, Object object) {
- if (node.isTwoStepsConstruction()) {
- constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
- } else {
- throw new YAMLException("Unexpected recursive mapping structure. Node: " + node);
- }
- }
+ @Override
+ public Object construct(Node node) {
+ MappingNode mnode = (MappingNode) node;
+ if (node.isTwoStepsConstruction()) {
+ return createDefaultMap(mnode.getValue().size());
+ } else {
+ return constructMapping(mnode);
+ }
}
- public static final class ConstructUndefined extends AbstractConstruct {
- @Override
- public Object construct(Node node) {
- throw new ConstructorException(null, null,
- "could not determine a constructor for the tag " + node.getTag(),
- node.getStartMark());
- }
+ @Override
+ @SuppressWarnings("unchecked")
+ public void construct2ndStep(Node node, Object object) {
+ if (node.isTwoStepsConstruction()) {
+ constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
+ } else {
+ throw new YAMLException("Unexpected recursive mapping structure. Node: " + node);
+ }
+ }
+ }
+
+ public static final class ConstructUndefined extends AbstractConstruct {
+
+ @Override
+ public Object construct(Node node) {
+ throw new ConstructorException(null, null,
+ "could not determine a constructor for the tag " + node.getTag(),
+ node.getStartMark());
}
+ }
}