Java JAXB2.x:如何从父类重写XmlElement注释-任务不可能?
为什么这是不可能的?它看起来很简单,但它的行为并不像预期的那样 摘要:类A使用聚合的DataA bean,而类B(类A的子类)使用聚合的DataB bean(而DataB扩展了DataA) 我编写这些测试类是为了可视化和解释我的问题: A类:Java JAXB2.x:如何从父类重写XmlElement注释-任务不可能?,java,inheritance,jaxb,marshalling,jaxb2,Java,Inheritance,Jaxb,Marshalling,Jaxb2,为什么这是不可能的?它看起来很简单,但它的行为并不像预期的那样 摘要:类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.xm
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类(我使用了字段注释以便对所有字段进行封送):
现在是类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;
}
}
其对应的数据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";
}
@XmlElement
public DataB getSource() {
return this.source;
}
现在,当我整理一个类A的实例时,它给出以下输出:
<?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 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>
1.
2.
3.
1.
2.
3.
因此,我对JAXB的期望是以下XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<source>
<string1>1</string1>
<string2>2</string2>
<string3>3</string3>
</source>
</root>
1.
2.
3.
有没有关于如何调整JAXB以产生预期结果的提示??
感谢您的反馈。不要在类B上注释源属性。源属性已映射到父类,不应再次映射到子类。由于您正在注释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);
}
}
更新
(参考实现)中可能存在错误。使用运行此更新的示例时,我得到以下输出:
<?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>
要使用MOXy作为JAXB实现,您需要在模型包(test)中提供一个名为JAXB.properties的文件,其中包含以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
非常感谢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";
}
}
你不需要用莫西。。 只需更改类B并使用@xml即可
@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>
1.
2.
1.
2.
3.
您可以使用以下方法:
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;
}
}
这个映射对我很有效。试着将
@xmlement
放在字段上而不是公共方法上是没有帮助的。我还尝试了在字段上不带任何XmlElement注释的XmlAccessType.FIELD,以及在GETTER上不带任何XmlElement注释的XmlAccessType.PROPERTY。。。这是虫子吗?就像这样,它不是真的有用。。。。如您所见,我将注释@xmlacessortype(xmlacesstype.NONE)放在这两个类中。。。因此,只有那些被XmlElement注释的元素得到了封送处理这在JRE主干中得到了修复:+1很高兴见到你:),1 Q。在基类中,它是私有的,那么它又如何进入子类呢?这是不是因为二传接球被压倒了?这太棒了,真的很有帮助@Oracle(Sun)的bzero-JavaSE6将包含JAXB参考实现Metro。我是MOXy技术负责人。您可以将MOXy与以下配置一起使用:1)eclipselink.jar 2)bundle:org.eclipse.persistence.asm、org.eclipse.persistence.core和org.eclipse.persistence.MOXy。@bzero-就JAXB而言,该属性属于DataA类型,因为这是超类上的属性类型。当数据的实例被封送时,xsi:type属性用于将其限定为子类型的实例。签出:行不使用MOXy:m.setProperty(“com.sun.xml.internal.bind.namespacePrefixMapper”,mapper);MOXy不支持namespacePrefixMapper,但是在MOXy中可以更轻松地实现这一点。MOXy将使用@XmlSchema注释中指定的前缀。有关示例,请参见:太棒了,谢谢!现在它完全可以正常工作了,就像它在一天前应该可以正常工作一样。嗨,这是一个有趣的方法,但是你有没有搞错什么?因为有类A和“B扩展了A”,所以A对B一无所知。在类A中应用实际引用类B的注释打破了面向对象的数据建模?也许你可以把@也应用到B类?那就可以了,我会试试看。
@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;
}
}