我正在使用JAXB来读写XML.我想要的是使用基本JAXB类进行编组,并使用继承的JAXB类进行解组.这是为了允许发送方Java应用程序将XML发送到另一个接收方Java应用程序.发送方和接收方将共享一个通用的JAXB库.我希望接收器将XML解组为特定于接收器的JAXB类,该类扩展了通用JAXB类.
例:
这是发件人使用的常见JAXB类.
@XmlRootElement(name="person")
public class Person {
public String name;
public int age;
}
Run Code Online (Sandbox Code Playgroud)
这是解组XML时使用的特定于接收器的JAXB类.接收器类具有特定于接收器应用的逻辑.
@XmlRootElement(name="person")
public class ReceiverPerson extends Person {
public doReceiverSpecificStuff() ...
}
Run Code Online (Sandbox Code Playgroud)
编组按预期工作.问题在于解组,Person尽管JAXBContext使用了子类的包名,它仍然是解组的ReceiverPerson.
JAXBContext jaxbContext = JAXBContext.newInstance(package name of ReceiverPerson);
Run Code Online (Sandbox Code Playgroud)
我想要的是解散ReceiverPerson.我已经能够做到这一点的唯一方法是删除@XmlRootElement从Person.不幸的是,这样做可以防止Person被编组.这就好像JAXB从基类开始并向下运行,直到找到@XmlRootElement具有相应名称的第一个.我试着加入createPerson()该方法返回ReceiverPerson到ObjectFactory但这并不能帮助.
iva*_*off 20
你正在使用JAXB 2.0吗?(自JDK6起)
有一节课:
javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType>
Run Code Online (Sandbox Code Playgroud)
哪一个可以子类化,并覆盖以下方法:
public abstract BoundType unmarshal(ValueType v) throws Exception;
public abstract ValueType marshal(BoundType v) throws Exception;
Run Code Online (Sandbox Code Playgroud)
例:
public class YourNiceAdapter
extends XmlAdapter<ReceiverPerson,Person>{
@Override public Person unmarshal(ReceiverPerson v){
return v;
}
@Override public ReceiverPerson marshal(Person v){
return new ReceiverPerson(v); // you must provide such c-tor
}
}
Run Code Online (Sandbox Code Playgroud)
使用方法如下:
@Your_favorite_JAXB_Annotations_Go_Here
class SomeClass{
@XmlJavaTypeAdapter(YourNiceAdapter.class)
Person hello; // field to unmarshal
}
Run Code Online (Sandbox Code Playgroud)
我很确定,通过使用这个概念,您可以自己控制编组/解组过程(包括选择要构造的正确[sub | super]类型).
Pas*_*ent 20
以下代码段是使用绿灯进行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("</person"));
// Unmarshalling
context = JAXBContext.newInstance(Person.class, RecieverPerson.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader reader = new StringReader(outString);
RecieverPerson reciever = (RecieverPerson)unmarshaller.unmarshal(reader);
assertEquals(name, reciever.name);
assertEquals(age, reciever.age);
}
Run Code Online (Sandbox Code Playgroud)
重要的部分是使用该JAXBContext.newInstance(Class... classesToBeBound)方法进行解组上下文:
context = JAXBContext.newInstance(Person.class, RecieverPerson.class);
Run Code Online (Sandbox Code Playgroud)
通过此调用,JAXB将计算指定类的引用闭包并将识别RecieverPerson.测试通过.如果您更改参数顺序,您将得到一个java.lang.ClassCastException(所以它们必须按此顺序传递).
13r*_*ren 12
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
}
Run Code Online (Sandbox Code Playgroud)
[经过测试并确认可与JAXB合作].当继承层次结构中的多个类具有XmlRootElement批注时,它可以避免您注意到的问题.
这可以说是一种更简洁,更实用的方法,因为它将常见的数据模型分开,所以它根本不是"解决方法".
创建一个自定义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();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
62266 次 |
| 最近记录: |