我有一组给定的类来将xml解组到对象树中。现在,我得到了扩展的xml,并想用扩展的版本替换对象树中的一个类。
XML文件
<?xml version="1.0" encoding="UTF-8"?>
<RootNode_001>
<systemId>on the 4</systemId>
<systemName>give me some more</systemName>
<person>
<firstname>James</firstname>
<lastname>Brown</lastname>
<address>
<street>Funky</street>
<city>Town</city>
<type>HOME</type> <!-- this is the new field -->
</address>
</person>
</RootNode_001>
我用如下新字段创建一个新的地址类:
public class ExtAddress extends Address {
// inherit from address and add new field
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
现在,我尝试解组为对象树,并希望ExtAddress
像这样成为树的一部分:
public class Runner {
public static void main ( String argv[] ) throws Exception {
File file = new File( "basic.xml" );
Class cls = RootNode.class;
// create a context with the root node and the replacement class
JAXBContext jaxbContext = JAXBContext.newInstance( ExtAddress.class, cls );
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement jaxbElement = unmarshaller.unmarshal( new StreamSource( file ), cls );
RootNode rootNode = (RootNode) jaxbElement.getValue();
System.out.println( rootNode.getClass().getName() );
System.out.println( rootNode.getPerson().getClass().getName() );
// this returns Address but I want ExtAddress
System.out.println( rootNode.getPerson().getAddress().getClass().getName() );
}
}
到目前为止,我没有使用任何注释。未编组的对象树返回Address
,而不返回ExtAddress
。如果添加XmlType
注释,则会出现异常:
@XmlTyp( name = "address" )
ExtAddress extends Address {
...
}
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "address". Use @XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at jaxb.standard.Address
at jaxb.ExtAddress
我尝试了很多事情,但这似乎非常接近解决方案。如何告诉jaxb使用继承的类而不是原始的类。
我想在库中提供一组标准类,并能够以后在xml中出现新字段时将对象树作为扩展名进行更改。
答案 0 :(得分:0)
使用extAddress而不是address更改xml即可解决问题。
答案 1 :(得分:0)
您应该执行XML模式版本控制,而不是这样做,但是difficult要做得很好。链接文章中有pdf,您应该阅读它。
我过去曾经做过“选项3更改架构的targetNamespace”,因此,您可以执行以下操作:
每个版本都有不同的targetNamespaces:
targetNamespace="http://www.exampleSchema.com/v1.0"
targetNamespace="http://www.exampleSchema.com/v1.1"
...
,您可以为不同组中的每个命名空间生成必要的JAXB类:
com.example.schema.generated.v10
com.example.schema.generated.v11
...
从这里开始,您将如何尝试阅读它:
(当然,解组后您必须分别处理每个版本,这不一定很糟糕)
OR
您可以决定只使用一种架构,并且只能使用可选(minOccurs =“ 0”)元素扩展架构,这很丑陋,并且有一些限制,但有时就足够了。
OR
或者,您可以通过其他方式来实现:可以使用另一个支持架构版本控制的XML框架,例如:JMRI或JiBX (它们不是当前必需的,也不是积极开发的,只想显示一些示例。我真正想要链接的是另一种,但是很遗憾,我忘记了它的名字。)
答案 2 :(得分:0)
此处讨论了类似的主题:JAXB inheritance, unmarshal to subclass of marshaled class
使用jackson 2.8.6,您可以编写类似
的内容@Test
public void readXmlToSelfDefinedPojo2() throws Exception {
ObjectMapper mapper = new XmlMapper();
ExtAdress pojo = mapper.readValue(
Thread.currentThread().getContextClassLoader().getResourceAsStream("52109685.xml"),
ExtAdress.class);
System.out.println(toString(pojo));
}
public String toString(Object obj) throws JsonGenerationException, JsonMappingException, IOException{
StringWriter w = new StringWriter();
new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true).writeValue(w, obj);
return w.toString();
}
它将打印
{
"systemId" : "on the 4",
"type" : "test"
}
为
<?xml version="1.0" encoding="UTF-8"?>
<RootNode_001>
<systemId>on the 4</systemId>
<systemName>give me some more</systemName>
<type>test</type>
<person>
<firstname>James</firstname>
<lastname>Brown</lastname>
<address>
<street>Funky</street>
<city>Town</city>
<type>HOME</type> <!-- this is the new field -->
</address>
</person>
</RootNode_001>
和
@JsonIgnoreProperties(ignoreUnknown = true)
public class ExtAdress extends Adress {
public String type;
public ExtAdress() {
}
}
和
@JsonIgnoreProperties(ignoreUnknown = true)
public class Adress {
public String systemId;
public Adress() {
}
}