¿Es posible lograr la desorganización de una estructura de clase que utiliza el anidamiento de varios abstract
clases?
Dada una estructura de clase como esta:
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class Animal {}
public abstract class Mammal extends Animal {}
public class Tiger extends Mammal {}
public class Elephant extends Mammal {}
los @XmlRootElement
ed Zoo
La clase tiene una lista de animales:
@XmlElementWrapper(name = "animals")
@XmlElements({
@XmlElement(name = "elephant", type = Elephant.class),
@XmlElement(name = "tiger", type = Tiger.class)
})
private List<Animal> animals;
Creo que tienes la idea ... el XML para esto:
<?xml version="1.0" encoding="utf-8"?>
<zoo>
<animals>
<tiger>
<name>Richard</name>
<furry>true</furry>
</tiger>
<elephant>
<name>Otis</name>
<furry>false</furry>
</elephant>
<tiger>
<name>Kirk</name>
<furry>true</furry>
</tiger>
</animals>
</zoo>
Esto se ve bien, genial.
Ahora el JSON ...
{
"animals" : {
"tiger" : [ {
"name" : "Richard",
"furry" : true
}, {
"name" : "Kirk",
"furry" : true
} ],
"elephant" : [ {
"name" : "Otis",
"furry" : false
} ]
}
}
¿Por qué subgrupo el Mammal
objetos de clase en JSON?
Estoy usando EclipseLink MOXy 2.6 para la clasificación.
Respuestas
1 para la respuesta № 1RESPUESTA ORIGINAL
MOXy agrupa las teclas tiger
y elephant
para evitar repetirlos.
ACTUALIZACIÓN # 1
Por lo tanto, no es posible obtener un JSON como {"animales": [{"@type": "tigre"}, {"@tipo": elefante "}, ...]}?
Sí, es posible, solo necesita mapearlo de esa manera:
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 {
}
Manifestación
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"
} ]
}
ACTUALIZACIÓN # 2
Si desea mantener su representación XML actual y simplemente cambiar la representación JSON, puede usar la extensión de documento de mapeo externo de MOXy (consulte: http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html)
Documento de mapeo (oxm.xml)
Utilizaremos el documento de mapeo externo de MOXy para cambiar el mapeo para animals
campo en el Zoo
clase.
<?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>
Manifestación
En el código de demostración a continuación, creamos 2 instancias de JAXBContext
en el mismo modelo de dominio. El de JSON aprovecha un documento de mapeo externo para personalizar el mapeo. input.xml
es el documento XML de tu pregunta.
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);
}
}
Salida
A continuación se muestra el resultado de ejecutar el código de demostración.
{
"animals" : [ {
"@type" : "tiger",
"name" : "Richard",
"furry" : true
}, {
"@type" : "elephant",
"name" : "Otis",
"furry" : false
}, {
"@type" : "tiger",
"name" : "Kirk",
"furry" : true
} ]
}