Fix: dump omits JavaBean class name when used with an alias
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 60aab41..2a6c80c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -7,6 +7,9 @@
 	</properties>

 	<body>

 	     <release version="1.4-SNAPSHOT" date="in Mercurial" description="development">

+	         <action dev="py4fun" type="fix" issue="10" due-to="derrick.rice">

+                Fix: dump omits JavaBean class name when used with an alias (2009-07-28)

+            </action>

             <action dev="py4fun" type="add">

                 Generate sources and Javadoc (2009-07-27)

             </action>

diff --git a/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java b/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java
index 4fcb03a..84163b0 100644
--- a/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java
+++ b/src/main/java/org/yaml/snakeyaml/nodes/NodeTuple.java
@@ -9,6 +9,9 @@
     private final Node valueNode;
 
     public NodeTuple(Node keyNode, Node valueNode) {
+        if (keyNode == null || valueNode == null) {
+            throw new NullPointerException("Nodes must be provided.");
+        }
         this.keyNode = keyNode;
         this.valueNode = valueNode;
     }
@@ -20,4 +23,10 @@
     public Node getValueNode() {
         return valueNode;
     }
+
+    @Override
+    public String toString() {
+        return "<NodeTuple keyNode=" + keyNode.toString() + "; valueNode=" + valueNode.toString()
+                + ">";
+    }
 }
diff --git a/src/main/java/org/yaml/snakeyaml/representer/Representer.java b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
index 6adf9f3..ef4285f 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/Representer.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/Representer.java
@@ -91,20 +91,22 @@
         for (Property property : properties) {
             ScalarNode nodeKey = (ScalarNode) representData(property.getName());
             Object memberValue = property.get(javaBean);
+            boolean hasAlias = false;
+            if (this.representedObjects.containsKey(memberValue)) {
+                // the first occurrence of the node must keep the tag
+                hasAlias = true;
+            }
             Node nodeValue = representData(memberValue);
-            if (nodeValue instanceof MappingNode) {
+            // if possible try to avoid a global tag with a class name
+            if (nodeValue instanceof MappingNode && !hasAlias) {
                 // the node is a map, set or JavaBean
                 if (!Map.class.isAssignableFrom(memberValue.getClass())) {
                     // the node is set or JavaBean
                     if (property.getType() == memberValue.getClass()) {
                         // we do not need global tag because the property
                         // Class is the same as the runtime class
-                        if (node != nodeValue) {
-                            String memberTag = "tag:yaml.org,2002:map";
-                            nodeValue.setTag(memberTag);
-                        } else {
-                            // recursive node, keep the tag
-                        }
+                        String memberTag = "tag:yaml.org,2002:map";
+                        nodeValue.setTag(memberTag);
                     }
                 }
             } else if (memberValue != null && Enum.class.isAssignableFrom(memberValue.getClass())) {
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/BasicDumpTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/BasicDumpTest.java
new file mode 100644
index 0000000..dd4f077
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/BasicDumpTest.java
@@ -0,0 +1,81 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.yaml.snakeyaml.JavaBeanDumper;
+import org.yaml.snakeyaml.Util;
+import org.yaml.snakeyaml.Yaml;
+
+public class BasicDumpTest extends TestCase {
+
+    public void testTag() {
+        DataSource base = new DataSource();
+        JDBCDataSource baseJDBC = new JDBCDataSource();
+        baseJDBC.setParent(base);
+
+        ArrayList<DataSource> dataSources = new ArrayList<DataSource>();
+        // trying expected order first
+        dataSources.add(base);
+        dataSources.add(baseJDBC);
+
+        DataSources ds = new DataSources();
+        ds.setDataSources(dataSources);
+
+        Yaml yaml = new Yaml();
+        String output = yaml.dump(ds);
+
+        String etalon = Util.getLocalResource("javabeans/issue10-1.yaml");
+        assertEquals(etalon.trim(), output.trim());
+        Object obj = yaml.load(output);
+        DataSources dsOut = (DataSources) obj;
+        Iterator<DataSource> iter = dsOut.getDataSources().iterator();
+        assertFalse("Must be DataSource.", iter.next() instanceof JDBCDataSource);
+        assertTrue(iter.next() instanceof JDBCDataSource);
+    }
+
+    public void testTag2() {
+        DataSource base = new DataSource();
+        JDBCDataSource baseJDBC = new JDBCDataSource();
+        baseJDBC.setParent(base);
+
+        ArrayList<DataSource> dataSources = new ArrayList<DataSource>();
+        // trying expected order first
+        dataSources.add(base);
+        dataSources.add(baseJDBC);
+
+        DataSources ds = new DataSources();
+        ds.setDataSources(dataSources);
+
+        JavaBeanDumper yaml = new JavaBeanDumper();
+        String output = yaml.dump(ds);
+
+        String etalon = Util.getLocalResource("javabeans/issue10-2.yaml");
+        assertEquals(etalon.trim(), output.trim());
+    }
+
+    public void testTag3() {
+        DataSource base = new DataSource();
+        JDBCDataSource baseJDBC = new JDBCDataSource();
+        baseJDBC.setParent(base);
+
+        ArrayList<DataSource> dataSources = new ArrayList<DataSource>();
+        // trying expected order first
+        dataSources.add(baseJDBC);
+        dataSources.add(base);
+
+        DataSources ds = new DataSources();
+        ds.setDataSources(dataSources);
+
+        JavaBeanDumper yaml = new JavaBeanDumper();
+        String output = yaml.dump(ds);
+
+        String etalon = Util.getLocalResource("javabeans/issue10-3.yaml");
+        assertEquals(etalon.trim(), output.trim());
+    }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSource.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSource.java
new file mode 100644
index 0000000..8d7d7cf
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSource.java
@@ -0,0 +1,16 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+public class DataSource {
+    String name;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSources.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSources.java
new file mode 100644
index 0000000..5cfe77f
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/DataSources.java
@@ -0,0 +1,18 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+import java.util.List;
+
+public class DataSources {
+    List<DataSource> dataSources;
+
+    public List<DataSource> getDataSources() {
+        return dataSources;
+    }
+
+    public void setDataSources(List<DataSource> dataSources) {
+        this.dataSources = dataSources;
+    }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue10/JDBCDataSource.java b/src/test/java/org/yaml/snakeyaml/issues/issue10/JDBCDataSource.java
new file mode 100644
index 0000000..129bdd4
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue10/JDBCDataSource.java
@@ -0,0 +1,44 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.issues.issue10;
+
+public class JDBCDataSource extends DataSource {
+    String username;
+    String password;
+    String url;
+
+    DataSource parent;
+
+    public DataSource getParent() {
+        return parent;
+    }
+
+    public void setParent(DataSource parent) {
+        this.parent = parent;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+}
diff --git a/src/test/java/org/yaml/snakeyaml/nodes/NodeTupleTest.java b/src/test/java/org/yaml/snakeyaml/nodes/NodeTupleTest.java
new file mode 100644
index 0000000..94ce1c7
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/nodes/NodeTupleTest.java
@@ -0,0 +1,36 @@
+package org.yaml.snakeyaml.nodes;

+

+import junit.framework.TestCase;

+

+public class NodeTupleTest extends TestCase {

+

+    public void testNodeTuple1() {

+        Node node = new ScalarNode("!tag", "value1", null, null, null);

+        try {

+            new NodeTuple(null, node);

+            fail("Node must be provided.");

+        } catch (Exception e) {

+            assertEquals("Nodes must be provided.", e.getMessage());

+        }

+    }

+

+    public void testNodeTuple2() {

+        Node node = new ScalarNode("!tag", "value1", null, null, null);

+        try {

+            new NodeTuple(node, null);

+            fail("Node must be provided.");

+        } catch (Exception e) {

+            assertEquals("Nodes must be provided.", e.getMessage());

+        }

+    }

+

+    public void testToString() {

+        Node key = new ScalarNode("tag:yaml.org,2002:str", "key1", null, null, null);

+        Node value = new ScalarNode("tag:yaml.org,2002:str", "value1", null, null, null);

+        NodeTuple tuple = new NodeTuple(key, value);

+        assertEquals(

+                "<NodeTuple keyNode=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=key1)>; valueNode=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=value1)>>",

+                tuple.toString());

+    }

+

+}

diff --git a/src/test/resources/javabeans/issue10-1.yaml b/src/test/resources/javabeans/issue10-1.yaml
new file mode 100644
index 0000000..0c8786e
--- /dev/null
+++ b/src/test/resources/javabeans/issue10-1.yaml
@@ -0,0 +1,9 @@
+!!org.yaml.snakeyaml.issues.issue10.DataSources

+dataSources:

+- &id001 !!org.yaml.snakeyaml.issues.issue10.DataSource {name: null}

+- !!org.yaml.snakeyaml.issues.issue10.JDBCDataSource

+  name: null

+  parent: *id001

+  password: null

+  url: null

+  username: null
\ No newline at end of file
diff --git a/src/test/resources/javabeans/issue10-2.yaml b/src/test/resources/javabeans/issue10-2.yaml
new file mode 100644
index 0000000..3fde97a
--- /dev/null
+++ b/src/test/resources/javabeans/issue10-2.yaml
@@ -0,0 +1,9 @@
+dataSources:

+- &id001 !!org.yaml.snakeyaml.issues.issue10.DataSource

+  name: null

+- !!org.yaml.snakeyaml.issues.issue10.JDBCDataSource

+  name: null

+  parent: *id001

+  password: null

+  url: null

+  username: null
\ No newline at end of file
diff --git a/src/test/resources/javabeans/issue10-3.yaml b/src/test/resources/javabeans/issue10-3.yaml
new file mode 100644
index 0000000..65d512e
--- /dev/null
+++ b/src/test/resources/javabeans/issue10-3.yaml
@@ -0,0 +1,9 @@
+dataSources:

+- !!org.yaml.snakeyaml.issues.issue10.JDBCDataSource

+  name: null

+  parent: &id001

+    name: null

+  password: null

+  url: null

+  username: null

+- *id001
\ No newline at end of file