这是我的课程:
@XmlRootElement(name="Zoo") class Zoo { //@XmlElementRef public Collection<? extends Animal> animals; } @XmlAccessorType(XmlAccessType.FIELD) @XmlSeeAlso({Bird.class, Cat.class, Dog.class}) @XmlDiscriminatorNode("@type") abstract class Animal { @XmlElement public String name; } @XmlDiscriminatorValue("Bird") @XmlRootElement(name="Bird") class Bird extends Animal { @XmlElement public String wingSpan; @XmlElement public String preferredFood; } @XmlDiscriminatorValue("Cat") @XmlRootElement(name="Cat") class Cat extends Animal { @XmlElement public String favoriteToy; } @XmlDiscriminatorValue("Dog") @XmlRootElement(name="Dog") class Dog extends Animal { @XmlElement public String breed; @XmlElement public String leashColor; }
这是序列化的JSON:
{ "animals": [ { "type": "Bird", "name": "bird-1", "wingSpan": "6 feets", "preferredFood": "food-1" }, { "type": "Cat", "name": "cat-1", "favoriteToy": "toy-1" }, { "type": "Dog", "name": "dog-1", "breed": "bread-1", "leashColor": "black" } ] }
这是反序列化器代码:
public static <T> T Deserialize_Moxy(String jsonStr, Class<?>[] cl) throws JAXBException { InputStream is = new ByteArrayInputStream(jsonStr.getBytes()); JAXBContext jc = JAXBContext.newInstance(cl); Unmarshaller unmarshaller = jc.createUnmarshaller(); // Marshal to JSON unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json"); unmarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false); @SuppressWarnings("unchecked") T obj = (T)unmarshaller.unmarshal(is); return obj; }
这是例外:
Exception in thread "main" javax.xml.bind.UnmarshalException - with linked exception: [Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.XMLMarshalException Exception Description: A descriptor with default root element was not found in the project] at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1014) at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:147) at com.bp.samples.json.generics.Foo.Deserialize_Moxy(Foo.java:271) at com.bp.samples.json.generics.Foo.main(Foo.java:111) Caused by: Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.XMLMarshalException Exception Description: A descriptor with default root element was not found in the project at org.eclipse.persistence.exceptions.XMLMarshalException.noDescriptorWithMatchingRootElement(XMLMarshalException.java:143) at org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler.startElement(SAXUnmarshallerHandler.java:222) at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:161) at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:118) at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:827) at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:350) at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:334) at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:407) at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:133) ... 2 more
还有一个关于序列化JSON的问题:是否有一种方法可以使JSON序列化程序发布“ @type”而不是“ type”。当前,它看起来像具有属性“类型”的对象。如果我们可以用“ @”修饰它,那么显然这更多的是类型信息而不是属性。
谢谢,Behzad
以下是我对您的两个问题的回答:
问题#1-例外
当使用该MarshallerProperties.JSON_INCLUDE_ROOT属性关闭根元素时,则需要使用一种unmarshal采用Class参数的方法来告诉MOXy您想要解组的对象的类型。
MarshallerProperties.JSON_INCLUDE_ROOT
unmarshal
Class
StreamSource json = new StreamSource("src/forum14246033/input.json"); Zoo zoo = unmarshaller.unmarshal(json, Zoo.class).getValue();
问题2
该@前缀表示字段/属性映射为XML属性。您可以使用该JAXBContextProperties.JSON_ATTRIBUTE_PREFIX属性指定前缀以限定映射到XML属性的数据。
@
JAXBContextProperties.JSON_ATTRIBUTE_PREFIX
properties.put(JAXBContextProperties.JSON_ATTRIBUTE_PREFIX, "@");
完整的例子
演示版
package forum14246033; 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>(2); 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/forum14246033/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 /输出
{ "animals" : [ { "@type" : "Bird", "name" : "bird-1", "wingSpan" : "6 feets", "preferredFood" : "food-1" }, { "@type" : "Cat", "name" : "cat-1", "favoriteToy" : "toy-1" }, { "@type" : "Dog", "name" : "dog-1", "breed" : "bread-1", "leashColor" : "black" } ] }
领域模型
我不建议在域模型中使用公共字段,但是如果您这样做,则可以将元数据缩减为以下内容:
动物园
import java.util.Collection; class Zoo { public Collection<? extends Animal> animals; }
动物
import javax.xml.bind.annotation.XmlSeeAlso; import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode; @XmlSeeAlso({Bird.class, Cat.class, Dog.class}) @XmlDiscriminatorNode("@type") abstract class Animal { public String name; }
鸟
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue; @XmlDiscriminatorValue("Bird") class Bird extends Animal { public String wingSpan; public String preferredFood; }
jaxb.properties
要将MOXy指定为JAXB(JSR-222)提供程序,您需要jaxb.properties在与域模型相同的程序包中包含一个名为的文件,并包含以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory