ORIGINAL ANSWER
MOXy groups the keys tiger
and elephant
to avoid repeating them.
UPDATE #1
So it not possible to get a JSON like { 'animals': [ {'@type': 'tiger'}, {'@type': elephant'}, ... ] }?
Yes it's possible, you just need to map it that way:
Zoo
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class Zoo {
private List<Animal> animals;
}
Animal
import javax.xml.bind.annotation.*;
@XmlSeeAlso({Elephant.class, Tiger.class})
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class Animal {
}
Demo
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
properties.put(JAXBContextProperties.JSON_ATTRIBUTE_PREFIX, "@");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Zoo.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum19384491/input.json");
Zoo zoo = unmarshaller.unmarshal(json, Zoo.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(zoo, System.out);
}
}
input.json/Output
{
"animals" : [ {
"@type" : "tiger"
}, {
"@type" : "elephant"
}, {
"@type" : "tiger"
} ]
}
UPDATE #2
If you want to keep your current XML representation and just change the JSON representation you could use MOXy's external mapping document extension (see: http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html)
Mapping Document (oxm.xml)
We will use MOXy's external mapping document to change the mapping for the animals
field on the Zoo
class.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum19384491">
<java-types>
<java-type name="Zoo">
<java-attributes>
<xml-element java-attribute="animals"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
In the demo code below we create 2 instances of JAXBContext
on the same domain model. The one for JSON leverages an external mapping document to customize the mapping. input.xml
is the XML document from your question.
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 {
JAXBContext xmlJC = JAXBContext.newInstance(Zoo.class);
Unmarshaller unmarshaller = xmlJC.createUnmarshaller();
File xml = new File("src/forum19384491/input.xml");
Zoo zoo = (Zoo) unmarshaller.unmarshal(xml);
Map<String, Object> properties = new HashMap<String, Object>(4);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum19384491/oxm.xml");
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
properties.put(JAXBContextProperties.JSON_ATTRIBUTE_PREFIX, "@");
JAXBContext jsonJC = JAXBContext.newInstance(new Class[] {Zoo.class}, properties);
Marshaller marshaller = jsonJC.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(zoo, System.out);
}
}
Output
Below is the output from running the demo code.
{
"animals" : [ {
"@type" : "tiger",
"name" : "Richard",
"furry" : true
}, {
"@type" : "elephant",
"name" : "Otis",
"furry" : false
}, {
"@type" : "tiger",
"name" : "Kirk",
"furry" : true
} ]
}