From 5c1a2fc1427f5f42f6a1cae4a9b902b0a0cd1457 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Sun, 13 Dec 2020 09:52:50 +0100
Subject: [PATCH] Workaround for fixing node type attribute issue

---
 .../datamodel/RemoveDuplicateTypeAdapter.java | 25 +++++++++++++++++++
 .../ivoa/xml/vospace/v2/ContainerNode.java    |  3 +++
 .../java/net/ivoa/xml/vospace/v2/Node.java    | 15 ++++++++++-
 .../net/ivoa/xml/vospace/v2/NodeTest.java     |  4 +--
 4 files changed, 44 insertions(+), 3 deletions(-)
 create mode 100644 src/main/java/it/inaf/oats/vospace/datamodel/RemoveDuplicateTypeAdapter.java

diff --git a/src/main/java/it/inaf/oats/vospace/datamodel/RemoveDuplicateTypeAdapter.java b/src/main/java/it/inaf/oats/vospace/datamodel/RemoveDuplicateTypeAdapter.java
new file mode 100644
index 0000000..7314707
--- /dev/null
+++ b/src/main/java/it/inaf/oats/vospace/datamodel/RemoveDuplicateTypeAdapter.java
@@ -0,0 +1,25 @@
+package it.inaf.oats.vospace.datamodel;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import net.ivoa.xml.vospace.v2.Node;
+
+/**
+ * JAXB automatically generates the xsi:type attribute, however it doesn't fill
+ * it for the root node (it seems that this is by design). Since we need it, we
+ * manually added it on the Node class, but this causes a duplication of the
+ * attribute in the children nodes. This adapter is applied to children nodes to
+ * avoid the duplication by setting the field to null.
+ */
+public class RemoveDuplicateTypeAdapter extends XmlAdapter<Node, Node> {
+
+    @Override
+    public Node unmarshal(Node node) throws Exception {
+        return node;
+    }
+
+    @Override
+    public Node marshal(Node node) throws Exception {
+        node.removeType();
+        return node;
+    }
+}
diff --git a/src/main/java/net/ivoa/xml/vospace/v2/ContainerNode.java b/src/main/java/net/ivoa/xml/vospace/v2/ContainerNode.java
index 03a7880..d25747a 100644
--- a/src/main/java/net/ivoa/xml/vospace/v2/ContainerNode.java
+++ b/src/main/java/net/ivoa/xml/vospace/v2/ContainerNode.java
@@ -6,6 +6,7 @@
 //
 package net.ivoa.xml.vospace.v2;
 
+import it.inaf.oats.vospace.datamodel.RemoveDuplicateTypeAdapter;
 import java.util.ArrayList;
 import java.util.List;
 import javax.xml.bind.annotation.XmlAccessType;
@@ -14,6 +15,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 /**
  *
@@ -66,6 +68,7 @@ public class ContainerNode
     // This should simplify usage and JSON compatibility.
     @XmlElement(name = "node")
     @XmlElementWrapper(name = "nodes", required = true)
+    @XmlJavaTypeAdapter(RemoveDuplicateTypeAdapter.class)
     protected List<Node> nodes;
 
     public List<Node> getNodes() {
diff --git a/src/main/java/net/ivoa/xml/vospace/v2/Node.java b/src/main/java/net/ivoa/xml/vospace/v2/Node.java
index e682221..9017944 100644
--- a/src/main/java/net/ivoa/xml/vospace/v2/Node.java
+++ b/src/main/java/net/ivoa/xml/vospace/v2/Node.java
@@ -59,10 +59,23 @@ public class Node {
     protected PropertyList properties;
 
     // <edit>
+    // Used for generating missing type attribute for root node. For child nodes it is filled automatically.
+    @XmlAttribute(name = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance", required = false)
+    private String type;
+
+    /* This method exists to fix the issue with type attribute. See RemoveDuplicateTypeAdapter class. */
+    public void removeType() {
+        this.type = null;
+    }
+    
+    public Node() {
+        type = getType();
+    }
+    
     // Needed for handling inheritance in JSON (in XML, type attribute is automatically generated by JAXB).
     @JsonProperty
     @XmlTransient
-    public String getType() {
+    public final String getType() {
         return "vos:" + getClass().getSimpleName();
     }
     // </edit>
diff --git a/src/test/java/net/ivoa/xml/vospace/v2/NodeTest.java b/src/test/java/net/ivoa/xml/vospace/v2/NodeTest.java
index 09b23f5..3612036 100644
--- a/src/test/java/net/ivoa/xml/vospace/v2/NodeTest.java
+++ b/src/test/java/net/ivoa/xml/vospace/v2/NodeTest.java
@@ -36,7 +36,7 @@ public class NodeTest {
 
         Document doc = loadDocument(xml);
         assertEquals("vos:node", doc.getDocumentElement().getNodeName());
-        //assertEquals("vos:ContainerNode", doc.getDocumentElement().getAttribute("xsi:type"));
+        assertEquals("vos:ContainerNode", doc.getDocumentElement().getAttribute("xsi:type"));
 
         assertTrue(xml.contains("<vos:nodes>"));
         assertTrue(xml.contains("xsi:type=\"vos:DataNode\""));
@@ -58,7 +58,7 @@ public class NodeTest {
 
         String json = MAPPER.writeValueAsString(root);
         System.out.println(json);
-        
+
         assertThat(json, hasJsonPath("$.type", is("vos:ContainerNode")));
 
         assertThat(json, hasJsonPath("$.nodes[0].type", is("vos:DataNode")));
-- 
GitLab