我正在使用JAXB来读写XML.我想要的是使用基本JAXB类进行编组,并使用继承的JAXB类进行解组.这是为了允许发送方Java应用程序将XML发送到另一个接收方Java应用程序.发送方和接收方将共享一个通用的JAXB库.我希望接收器将XML解组为特定于接收器的JAXB类,该类扩展了通用JAXB类.
例:
这是发件人使用的常见JAXB类.
@XmlRootElement(name="person") public class Person { public String name; public int age; }
这是解组XML时使用的特定于接收器的JAXB类.接收器类具有特定于接收器应用的逻辑.
@XmlRootElement(name="person") public class ReceiverPerson extends Person { public doReceiverSpecificStuff() ... }
编组按预期工作.问题在于解组,Person
尽管JAXBContext使用了子类的包名,它仍然是解组的ReceiverPerson
.
JAXBContext jaxbContext = JAXBContext.newInstance(package name of ReceiverPerson);
我想要的是解散ReceiverPerson
.我已经能够做到这一点的唯一方法是删除@XmlRootElement
从Person
.不幸的是,这样做可以防止Person
被编组.这就好像JAXB从基类开始并向下运行,直到找到@XmlRootElement
具有相应名称的第一个.我试着加入createPerson()
该方法返回ReceiverPerson
到ObjectFactory
但这并不能帮助.
你正在使用JAXB 2.0吗?(自JDK6起)
有一节课:
javax.xml.bind.annotation.adapters.XmlAdapter
哪一个可以子类化,并覆盖以下方法:
public abstract BoundType unmarshal(ValueType v) throws Exception; public abstract ValueType marshal(BoundType v) throws Exception;
例:
public class YourNiceAdapter extends XmlAdapter{ @Override public Person unmarshal(ReceiverPerson v){ return v; } @Override public ReceiverPerson marshal(Person v){ return new ReceiverPerson(v); // you must provide such c-tor } }
使用方法如下:
@Your_favorite_JAXB_Annotations_Go_Here class SomeClass{ @XmlJavaTypeAdapter(YourNiceAdapter.class) Person hello; // field to unmarshal }
我很确定,通过使用这个概念,您可以自己控制编组/解组过程(包括选择要构造的正确[sub | super]类型).
以下代码段是使用绿灯进行Junit 4测试的方法:
@Test public void testUnmarshallFromParentToChild() throws JAXBException { Person person = new Person(); int age = 30; String name = "Foo"; person.name = name; person.age= age; // Marshalling JAXBContext context = JAXBContext.newInstance(person.getClass()); Marshaller marshaller = context.createMarshaller(); StringWriter writer = new StringWriter(); marshaller.marshal(person, writer); String outString = writer.toString(); assertTrue(outString.contains("重要的部分是使用该
JAXBContext.newInstance(Class... classesToBeBound)
方法进行解组上下文:context = JAXBContext.newInstance(Person.class, RecieverPerson.class);通过此调用,JAXB将计算指定类的引用闭包并将识别
RecieverPerson
.测试通过.如果您更改参数顺序,您将得到一个java.lang.ClassCastException
(所以它们必须按此顺序传递).
3> 13ren..:Subclass Person两次,一次用于接收器,一次用于发送者,并且只将XmlRootElement放在这些子类上(离开超类
Person
,没有XmlRootElement).请注意,发送方和接收方都共享相同的JAXB基类.@XmlRootElement(name="person") public class ReceiverPerson extends Person { // receiver specific code } @XmlRootElement(name="person") public class SenderPerson extends Person { // sender specific code (if any) } // note: no @XmlRootElement here public class Person { // data model + jaxb annotations here }[经过测试并确认可与JAXB合作].当继承层次结构中的多个类具有XmlRootElement批注时,它可以避免您注意到的问题.
这可以说是一种更简洁,更实用的方法,因为它将常见的数据模型分开,所以它根本不是"解决方法".
4> vocaro..:创建一个自定义ObjectFactory以在解组期间实例化所需的类.例:
JAXBContext context = JAXBContext.newInstance("com.whatever.mypackage"); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setProperty("com.sun.xml.internal.bind.ObjectFactory", new ReceiverPersonObjectFactory()); return unmarshaller; public class ReceiverPersonObjectFactory extends ObjectFactory { public Person createPerson() { return new ReceiverPerson(); } }