I work with a datamodel created using JAXB, from that I can generate XML directly
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
<metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#" xmlns:ext="http://musicbrainz.org/ns/ext#-2.0">
<artist-list offset="0" count="1">
<artist ext:score="100" type="Group" id="4302e264-1cf0-4d1f-aca7-2a6f89e34b36">
<name>Farming Incident</name>
<ipi-list>
<ipi>1001</ipi>
</ipi-list>
</artist>
</artist-list>
</metadata>
and with the help of Jersey also generate JSon using Natural notation
"artist-list":
{"offset":0,
"count":1,
"artist":[
{"score":"100",
"type":"Group",
"id":"4302e264-1cf0-4d1faca7-2a6f89e34b36",
"name":"Farming Incident",
"ipi-list":
{
"ipi":[
"1001"
]
}
}]
}
The Xml is fine, the json is nearly fine except that because Json directly supports arrays having elements like ipi-list and artist-list doesnt seem very json, is it possible to generate more json like json from my model ?
Additional Information as Requested The json is generated from this MMD schema http://svn.musicbrainz.org/mmd-schema/trunk/brainz-mmd2-jaxb/src/main/resources/musicbrainz_mmd-2.0.xsd using JAXB and Jersey , see http://svn.musicbrainz.org/search_server/trunk/servlet/src/main/java/org/musicbrainz/search/servlet/mmd2/ResultsWriter.java and http://svn.musicbrainz.org/search_server/trunk/servlet/src/main/java/org/musicbrainz/search/servlet/mmd2/ArtistWriter.java
The point is that I want to be able to generate Json and XML from one schema with the minimum of fuss, but apparently the Json doesn't look right so Im looking for a way to improve it (I don't really have any experience of json myself)
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
You could leverage the JSON-Binding and external mapping document in EclipseLink JAXB (MOXy) to support your use case.
External Mapping File (oxml.xml)
You can use the @XmlPath(".")
extension in MOXy to flatten parts of your object model. Specify a path of "."
tells MOXy to include the referenced object in the parent node.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum10699038">
<java-types>
<java-type name="Metadata">
<java-attributes>
<xml-element java-attribute="artistList" xml-path="."/>
</java-attributes>
</java-type>
<java-type name="Artist">
<java-attributes>
<xml-element java-attribute="ipiList" xml-path="."/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
jaxb.properties
To specify MOXy as your JAXB provider you need to add a file called jaxb.properties
in the same package as your domain model with the following entry.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
The code below populates the object model from your XML document, and then marshalled to JSON. It demonstrates how to leverage the external mapping file and put MOXy in JSON mode.
package forum10699038;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
// READ FROM XML
JAXBContext jcXML = JAXBContext.newInstance(Metadata.class);
File xml = new File("src/forum10699038/input.xml");
Unmarshaller unmarshaller = jcXML.createUnmarshaller();
Metadata metadata = (Metadata) unmarshaller.unmarshal(xml);
// WRITE TO JSON
Map<String, Object> properties = new HashMap<String, Object>(3);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum10699038/oxm.xml");
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jcJSON = JAXBContext.newInstance(new Class[] {Metadata.class}, properties);
Marshaller marshaller = jcJSON.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(metadata, System.out);
}
}
Output
{
"artist" : [ {
"id" : "4302e264-1cf0-4d1f-aca7-2a6f89e34b36",
"type" : "Group",
"score" : "100",
"name" : "Farming Incident",
"ipi" : [ "1001" ]
} ]
}
MOXy and Jersey
You can easily use MOXy as your JSON provider in a JAXB-RS environment such as Jersey:
OTHER FILES
Below are versions of your files I created to make sure everything worked properly.
input.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#" xmlns:ext="http://musicbrainz.org/ns/ext#-2.0">
<artist-list offset="0" count="1">
<artist ext:score="100" type="Group"
id="4302e264-1cf0-4d1f-aca7-2a6f89e34b36">
<name>Farming Incident</name>
<ipi-list>
<ipi>1001</ipi>
</ipi-list>
</artist>
</artist-list>
</metadata>
Metadata
package forum10699038;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class Metadata {
@XmlElement(name="artist-list")
ArtistList artistList;
}
ArtistList
package forum10699038;
import java.util.List;
public class ArtistList {
private List<Artist> artist;
}
Artist
package forum10699038;
import javax.xml.bind.annotation.*;
@XmlType(propOrder={"name", "ipiList"})
public class Artist {
@XmlAttribute
private String id;
@XmlAttribute
private String type;
@XmlAttribute(namespace="http://musicbrainz.org/ns/ext#-2.0")
private String score;
@XmlElement(name="ipi-list")
private IPIList ipiList;
private String name;
}
IPList
package forum10699038;
import java.util.List;
public class IPIList {
private List<String> ipi;
}
package-info
@XmlSchema(
namespace = "http://musicbrainz.org/ns/mmd-2.0#",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns={
@XmlNs(prefix="", namespaceURI = "http://musicbrainz.org/ns/mmd-2.0#")
}
)
@XmlAccessorType(XmlAccessType.FIELD)
package forum10699038;
import javax.xml.bind.annotation.*;
The JSON being created by Jersey is an exact JSOON representation of that model provided on the site. The problem you are facing here is that the site is providing an awkward data model, not that the framework is not doing the right thing.
Why does this service return an object of type artist-list instead of returning a list of artists? Why does the service have an ipi-list object also? The real question you should be asking should be, how should this be modeled to work better with all technologies.
I personally don't like annotations too much. Have a habit of generating JSON/XML in plain code. :)
For example with Jackson (Gson also similar):
mapper = new ObjectMapper();
JsonNode root = mapper.createObjectNode();
JsonNode artist = mapper.createObjectNode();
artist.put("score", "100");
root.put("artist-list", artist);
ArrayNode ipiList = mapper.createArrayNode();
ipi.add("1001");
artist.put("ipi-list", ipiList);
It may looks a lot of work on surface. But for me this is very clear way of mapping JSON to objects. Basically having toJson() method in entity classes is my usual practice. Here is an example: https://github.com/richardzcode/metrics/blob/master/src/main/java/com/rz/metrics/core/entities
It is just me though.
For JAXB I believe you need to annotate your entity like below:
@XmlElement(name = "ipi-list")
private List<Ipi> ipi;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With