fix issue 69: Serialise Iterator and Iterable as sequences
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d3a8f69..cc8f903 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -7,6 +7,9 @@
</properties>
<body>
<release version="1.7" date="in Mercurial" description="development">
+ <action dev="py4fun" type="update" issue="69">
+ Serialise Iterator and Iterable as sequences (2010-06-25)
+ </action>
<action dev="py4fun" type="update" due-to="maslovalex">
Change error message when 'No suitable constructor with N arguments found for class' (2010-06-23)
</action>
diff --git a/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
index 738689f..939bb2f 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
@@ -21,6 +21,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -51,7 +52,8 @@
*/
protected Represent nullRepresenter;
@SuppressWarnings("unchecked")
- protected final Map<Class, Represent> multiRepresenters = new HashMap<Class, Represent>();
+ //the order is important (map can be also a sequence of key-values)
+ protected final Map<Class, Represent> multiRepresenters = new LinkedHashMap<Class, Represent>();
private Character defaultStyle;
protected Boolean defaultFlowStyle;
protected final Map<Object, Node> representedObjects = new IdentityHashMap<Object, Node>();
@@ -125,8 +127,12 @@
return representScalar(tag, value, null);
}
- protected Node representSequence(Tag tag, List<? extends Object> sequence, Boolean flowStyle) {
- List<Node> value = new ArrayList<Node>(sequence.size());
+ protected Node representSequence(Tag tag, Iterable<? extends Object> sequence, Boolean flowStyle) {
+ int size = 10;// default for ArrayList
+ if (sequence instanceof List<?>) {
+ size = ((List<?>) sequence).size();
+ }
+ List<Node> value = new ArrayList<Node>(size);
SequenceNode node = new SequenceNode(tag, value, flowStyle);
representedObjects.put(objectToRepresent, node);
boolean bestStyle = true;
diff --git a/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
index 80e5258..b9dfafb 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/Representer.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
@@ -183,7 +183,7 @@
// apply map tag where class is the same
Class<? extends Object> t = arguments[0];
SequenceNode snode = (SequenceNode) node;
- List<Object> memberList = (List<Object>) object;
+ Iterable<Object> memberList = (Iterable<Object>) object;
Iterator<Object> iter = memberList.iterator();
for (Node childNode : snode.getValue()) {
Object member = iter.next();
diff --git a/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
index 3d29a81..6c5a755 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
@@ -21,6 +21,7 @@
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -47,14 +48,17 @@
this.representers.put(Boolean.class, new RepresentBoolean());
this.representers.put(Character.class, new RepresentString());
this.representers.put(byte[].class, new RepresentByteArray());
- this.multiRepresenters.put(Number.class, new RepresentNumber());
- this.multiRepresenters.put(List.class, new RepresentList());
this.multiRepresenters.put(Map.class, new RepresentMap());
+ this.multiRepresenters.put(Number.class, new RepresentNumber());
this.multiRepresenters.put(Set.class, new RepresentSet());
+ // iterator must go after other collections since otherwise maps and
+ // sets will be represented as sequences
+ this.multiRepresenters.put(Iterable.class, new RepresentIterable());
+ this.multiRepresenters.put(Iterator.class, new RepresentIterator());
this.multiRepresenters.put(new Object[0].getClass(), new RepresentArray());
this.multiRepresenters.put(Date.class, new RepresentDate());
- this.multiRepresenters.put(Calendar.class, new RepresentDate());
this.multiRepresenters.put(Enum.class, new RepresentEnum());
+ this.multiRepresenters.put(Calendar.class, new RepresentDate());
classTags = new HashMap<Class<? extends Object>, Tag>();
}
@@ -165,10 +169,32 @@
}
}
- protected class RepresentList implements Represent {
+ protected class RepresentIterable implements Represent {
@SuppressWarnings("unchecked")
public Node representData(Object data) {
- return representSequence(getTag(data.getClass(), Tag.SEQ), (List<Object>) data, null);
+ return representSequence(getTag(data.getClass(), Tag.SEQ), (Iterable<Object>) data,
+ null);
+ }
+ }
+
+ protected class RepresentIterator implements Represent {
+ @SuppressWarnings("unchecked")
+ public Node representData(Object data) {
+ Iterator<Object> iter = (Iterator<Object>) data;
+ return representSequence(getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter),
+ null);
+ }
+ }
+
+ private class IteratorWrapper implements Iterable<Object> {
+ private Iterator<Object> iter;
+
+ public IteratorWrapper(Iterator<Object> iter) {
+ this.iter = iter;
+ }
+
+ public Iterator<Object> iterator() {
+ return iter;
}
}
diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresentIterableTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresentIterableTest.java
new file mode 100644
index 0000000..3d60770
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentIterableTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2008-2010, http://code.google.com/p/snakeyaml/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.yaml.snakeyaml.representer;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Test {@link issue69 http://code.google.com/p/snakeyaml/issues/detail?id=69}
+ */
+public class RepresentIterableTest extends TestCase {
+
+ public void testIterable() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new CounterFactory());
+ assertEquals("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", output);
+ }
+
+ public void testIterator() {
+ Yaml yaml = new Yaml();
+ String output = yaml.dump(new Counter(7));
+ assertEquals("[0, 1, 2, 3, 4, 5, 6]\n", output);
+ }
+
+ private class CounterFactory implements Iterable<Integer> {
+ public Iterator<Integer> iterator() {
+ return new Counter(10);
+ }
+ }
+
+ private class Counter implements Iterator<Integer> {
+ private int max = 0;
+ private int counter = 0;
+
+ public Counter(int max) {
+ this.max = max;
+ }
+
+ public boolean hasNext() {
+ return counter < max;
+ }
+
+ public Integer next() {
+ return counter++;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}