[英]JAXB 2.x : How to override an XmlElement annotation from parent class - Mission Impossible?
为什么这不可能呢? 看起来很简单,但是却没有达到预期的效果。
简介:A类使用聚合的DataA bean,而B类(A类的子类)使用聚合的DataB bean(而DataB扩展了DataA)。
我编写了这些测试类以可视化并解释我的问题:
A类:
package test;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name="root")
public class A {
private DataA source = new DataA();
@XmlElement(name="source")
public DataA getSource() {
return source;
}
public void setSource(DataA source) {
this.source = source;
}
}
及其DataA类(我使用FIELD注释,以便将所有字段编组):
package test;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@XmlAccessorType(XmlAccessType.FIELD)
public class DataA {
public String string1 = "1";
public String string2 = "2";
}
现在是类B(类A的子类):我的目标是重用A的功能,并使用DataB bean重用DataA bean的属性:
package test;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name="root")
public class B extends A {
private DataB source = new DataB();
public DataB getSource() {
return this.source;
}
public void setSource(DataB source) {
this.source = source;
}
}
其对应的DataB bean如下所示:
package test;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@XmlAccessorType(XmlAccessType.FIELD)
public class DataB extends DataA {
public String string3 = "3";
}
现在,当我编组A类的实例时,它给出以下输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source>
<string1>1</string1>
<string2>2</string2>
</source>
</root>
当我编组B类的实例时,我得到的结果非常相同:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source>
<string1>1</string1>
<string2>2</string2>
</source>
</root>
但是我希望string3也可以编组,但这只是编写bean DataA的属性! 为什么? 考虑到OOP时,这并不是很直观。
当我还在类B上设置@XmlElement批注时,如下所示:
@XmlElement
public DataB getSource() {
return this.source;
}
...然后,该属性将被编组两次,因为该属性一次由父类以及子类进行注释。 这也是我不想要的:
现在的输出是:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source xsi:type="dataB" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<string1>1</string1>
<string2>2</string2>
<string3>3</string3>
</source>
<source>
<string1>1</string1>
<string2>2</string2>
<string3>3</string3>
</source>
</root>
因此,我对JAXB的期望是以下XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source>
<string1>1</string1>
<string2>2</string2>
<string3>3</string3>
</source>
</root>
任何提示如何调整JAXB以产生预期的结果? 感谢您的任何反馈。
只是不要在类B上注释source属性。source属性映射在父类上,不应再次映射在子类上。 由于您正在注释get / set方法,因此将在类B上调用适当的get / set。
package test;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name="root")
public class B extends A {
private StringBuffer source = null;
public String getSource() {
return source.toString();
}
public void setSource(String source) {
this.source = new StringBuffer(source);
}
}
更新
Metro JAXB (参考实现)中可能存在错误。 当我使用EclipseLink JAXB(MOXy)运行此更新的示例时,得到以下输出:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<source>
<string1>1</string1>
<string2>2</string2>
</source>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="b">
<source xsi:type="dataB">
<string1>1</string1>
<string2>2</string2>
<string3>3</string3>
</source>
</root>
可以使用以下代码来复制它:
package test;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(A.class, B.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
A a = new A();
DataA da = new DataA();
da.string1 = "1";
da.string2 = "2";
a.setSource(da);
marshaller.marshal(a, System.out);
B b = new B();
DataB db = new DataB();
db.string1 = "1";
db.string2 = "2";
db.string3 = "3";
b.setSource(db);
marshaller.marshal(b, System.out);
}
}
要将MOXy用作JAXB实现,您需要在模型包(测试)中提供一个名为jaxb.properties的文件,其中包含以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
您不需要使用MOXy。只需更改B类并使用@XmlAlso。
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "root")
public class B extends A {
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({ DataA.class, DataB.class })
@XmlRootElement(name = "source")
@XmlType(name = "source")
public class DataA {
private String string1 = "1";
private String string2 = "2";
.....//getters and setters here
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "source")
public class DataB extends DataA {
private String string3 = "3";
.....//getters and setters here
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({ A.class, B.class })
@XmlRootElement(name = "root")
public class A {
private DataA source = new DataA();
public DataA getSource() {
return source;
}
public void setSource(DataA source) {
this.source = source;
}
}
B b = new B();
DataB db = new DataB();
db.setString1("1");
db.setString2("2");
db.setString3("3");
b.setSource(db);
marshaller.marshal(b, System.out);
最终将写入:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source>
<string1>1</string1>
<string2>2</string2>
</source>
</root>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="dataB">
<string1>1</string1>
<string2>2</string2>
<string3>3</string3>
</source>
</root>
您可以使用以下方法:
public interface Data {}
@XmlTransient
public abstract class A {
private Data data;
public Data getData(){
return data;
}
public void setData(Data data){
this.data = data;
}
}
@XmlAccessorType(XmlAccessType.NONE)
public class ClassA extends A {
// DataA implements Data
@XmlElement(type=DataA.class)
public Data getData(){
return super.getData();
}
public void setData(DataA data){
super.setData(data);
}
}
@XmlAccessorType(XmlAccessType.NONE)
public class ClassB extends A {
// DataB implements Data
private DataB data;
@XmlElement(type=DataB.class)
public DataA getData(){
return data;
}
public void setData(DataB data){
this.data = data;
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class ClassC {
@XmlElement
private ClassA classA;
@XmlElement
private ClassB classB;
public ClassA getClassA() {
return classA;
}
public void setClassA(ClassA classA) {
this.classA = classA;
}
public ClassB getClassB() {
return classB;
}
public ClassB setClassB(ClassB classB) {
this.classB = classB;
}
}
这个映射对我有用。
非常感谢Blaise提供了所有这些提示。 现在,MOXy可以在我的真实应用程序中使用真实bean正常工作。 真好!
我目前唯一的缺点是此配置代码中的最后一行不再起作用,因为MOXy当然使用了另一个名称空间前缀映射机制。
你有指针吗? 我搜索了MOXy文档并搜索了名称空间,但没有找到类似的东西。
NamespacePrefixMapper mapper = new PreferredMapper();
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper);
public static class PreferredMapper extends NamespacePrefixMapper {
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return "z";
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.