我想编组/解组继承另一个类的类的对象。
我从课程Thing
开始:
import java.util.List;
public class Thing {
private List<String> strings;
public List<String> getStrings() {
return strings;
}
public void setStrings(List<String> strings) {
this.strings = strings;
}
}
我扩展了这个类并使用JAXB注释对其进行注释。
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class JaxbThing extends Thing {
// @XmlElementWrapper(name = "list")
@XmlElementWrapper(name = "strings")
@XmlElement(name = "string")
public List<String> getStrings() {
return super.getStrings();
}
public void setStrings(List<String> string) {
super.setStrings(string);
}
}
然后我运行以下编组/解组程序:
import java.io.File;
import java.util.Arrays;
import javax.xml.bind.*;
public class Main {
public static void main(String[] args) {
JaxbThing t = new JaxbThing();
t.setStrings(Arrays.asList("a", "b", "c"));
try {
File f = new File("jaxb-file.xml");
JAXBContext context = JAXBContext.newInstance(JaxbThing.class);
Marshaller m = context.createMarshaller();
m.marshal(t, f);
Unmarshaller um = context.createUnmarshaller();
JaxbThing t2 = (JaxbThing) um.unmarshal(f);
System.out.println(t2.getStrings()); // I expect to see [a, b, c]
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
XML文件的内容是:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxbThing>
<strings>
<string>a</string>
<string>b</string>
<string>c</string>
</strings>
</jaxbThing>
一切似乎都是正确的。但解密的结果让我感到惊讶,因为控制台显示:
[
]
当我希望看到[a, b, c]
如果我以这种方式注释strings
属性:
@XmlElementWrapper(name = "list")
// @XmlElementWrapper(name = "strings")
@XmlElement(name = "string")
public List<String> getStrings() {
return super.getStrings();
}
然后控制台显示预期的[a, b, c]
。
我想JAXB unmarshaler正在使用类Thing
而不是JaxbThing
来解组XML文件内容。事实上,如果我用Thing
注释班级@XmlTransient
,我会得到预期的结果。
但是我不明白JAXB的这种行为。
有人可以解释一下吗?提前谢谢。
答案 0 :(得分:2)
问题是您正在覆盖父类的属性。 JAXB认为JAXBThing
有“
strings
的属性(继承自String
)映射到元素strings
。strings
的属性(在JAXBThing
上定义,映射到元素string
下的元素strings
。如果你在setStrings
上的JAXBThing
方法中设置了一个断点,你会看到它首先使用正确的数据调用,然后第二次调用它,其中包含覆盖初始值的错误数据set(因为它认为它们是共享setter的不同属性)。
您始终可以通过Thing
对其进行注释来删除@XmlTransient
课程。
import java.util.List;
import javax.xml.bind.annotation.XmlTransient;
@XmlTransient
public class Thing {
private List<String> strings;
public List<String> getStrings() {
return strings;
}
public void setStrings(List<String> strings) {
System.out.println("Thing" + strings);
this.strings = strings;
}
}
了解更多信息
答案 1 :(得分:0)
非常感谢您的回答。我做了你建议我的事。你是对的,setStrings
方法被调用两次。但是,至少在我的实验中,它永远不会被调用正确的值。
Bellow我提供修改后的示例代码。我添加了几行来跟踪执行情况。我还激活了marshaller格式化输出,以便更好地了解解组过程中会发生什么。
基类Thing
import java.util.List;
public class Thing {
private List<String> strings;
public List<String> getStrings() {
return strings;
}
public void setStrings(List<String> strings) {
/*new*/ System.out.printf("Thing.setStrings called. Prev. this.strings: %s (size %s). Received strings param: %s", this.strings, (this.strings!=null ? this.strings.size():"null"),strings);
this.strings = strings;
/*new*/ System.out.printf(". New this.strings: %s (size %s).%n%n", this.strings, (this.strings!=null ? this.strings.size():"null"));
}
}
扩展班级JaxbThing
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class JaxbThing extends Thing {
// @XmlElementWrapper(name = "list")
@XmlElementWrapper(name = "strings")
@XmlElement(name = "string")
public List<String> getStrings() {
return super.getStrings();
}
public void setStrings(List<String> string) {
/*new*/ System.out.printf("JaxbThing.setStrings called. Received strings param: %s (size %s)%n",string,(string !=null?string.size():"null"));
super.setStrings(string);
}
}
测试程序:
import java.io.File;
import java.util.Arrays;
import javax.xml.bind.*;
public class Main {
public static void main(String[] args) {
System.out.println("---- Initiallizing");
JaxbThing t = new JaxbThing();
t.setStrings(Arrays.asList("a", "b", "c"));
try {
File f = new File("jaxb-file.xml");
JAXBContext context = JAXBContext.newInstance(JaxbThing.class);
System.out.println("---- Marshalling");
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); /*new*/
m.marshal(t, f);
System.out.println("---- UnMarshalling");
Unmarshaller um = context.createUnmarshaller();
JaxbThing t2 = (JaxbThing) um.unmarshal(f);
System.out.println("---- Showing results");
System.out.println(t2.getStrings()); // I expect to see [a, b, c]
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
结果如下(我已对行编号):
1 ---- Initiallizing
2 JaxbThing.setStrings called. Received strings param: [a, b, c] (size 3)
3 Thing.setStrings called. Prev. this.strings: null (size null). Received strings param: [a, b, c]. New this.strings: [a, b, c] (size 3).
4
5 ---- Marshalling
6 ---- UnMarshalling
7 JaxbThing.setStrings called. Received strings param: [] (size 0)
8 Thing.setStrings called. Prev. this.strings: null (size null). Received strings param: []. New this.strings: [] (size 0).
9
10 JaxbThing.setStrings called. Received strings param: [
] (size 1)
11 Thing.setStrings called. Prev. this.strings: [
] (size 1). Received strings param: [
]. New this.strings: [
] (size 1).
12
13 ---- Showing results
14 [
]
在解组时,会构建一个新的JaxbThing
,首先使用0长度的字符串列表调用其JaxbThing.setStrings
(第7行)。因此,调用Thing.setStrings
(第8行)。对象的字符串字段(this.strings
)的先前值为null。然后,再次调用JaxbThing.setStrings
(第10行),但现在有一个字符串列表,其中包含一个带有'\ n'字符和4个空格的字符串(我猜这对应于XML文件的缩进) )。两句话:
JaxbThing.setStrings
(除非我没有看到它)。JaxbThing.setStrings
(第10行)会导致第二次调用Thing.setStrings
(第11行)。但是现在this.strings
的先前值不是在第8行中对Thing.setStrings
的上一次调用中设置的0长度字符串列表。它已经是'\ n'字符加上4个空格,即作为参数传递。解释这种行为的任何线索?