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 0000000000000000000000000000000000000000..73147078df94010c986d6165982764b1e9966619 --- /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 03a78806311d14481a9bc30e856b9a087154d30f..d25747a60a39bdb048c9801700dd2e25ece7270a 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 e682221207bc975ba36e194d149881da96e40e73..9017944d9170618665e997993d522b8ac19b2e96 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 09b23f51da9a417af184f4230db29b527b5c6994..361203673c591c65356867563243260d5958e57e 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")));