我如何使用相同的 JAXB class 编组和解组到不同的命名空间?
How can I use same JAXB class to marshall and unmarshall into different namespaces?
注意: 这是 Java 7. 此外,我没有使用 JAXB 从模式生成任何内容。我 only/merely 想使用 JAXB 反序列化现有 SOAP 消息的片段。所以 JAXB bean 是 "hand-written".
我正在尝试使用 JAXB 反序列化以下 XML。我没有 可以访问它作为字符串。相反,我将其作为 org.w3c.dom.Element
对象获取:
<SynchInfo xmlns="urn:InitronSOAPService">
<HandshakeInfo>
<dnsName>foo.bar</dnsName>
<ip>1.2.3.4</ip>
<id>TheId</id>
<key>SomeKey</key>
<version>1.0</version>
</HandshakeInfo>
</SynchInfo>
但我还想将 HandshakeInfo
个实例编组到一个 SOAPBody
中,它是属于 不同命名空间 .[=26 的消息的一部分=]
我首先尝试写一个 HandshakeInfo
class 完全没有提到命名空间:
@XmlRootElement(name = "HandshakeInfo")
@XmlAccessorType(XmlAccessType.NONE)
final private static class HandshakeInfo
{
private String version;
private String id;
private String key;
private String ip;
private String dnsName;
public String getVersion() {
return version;
}
@XmlElement(name = "version")
public void setVersion(String version) {
this.version = version;
}
public String getId() {
return id;
}
@XmlElement(name = "id")
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
@XmlElement(name = "key")
public void setKey(String key) {
this.key = key;
}
public String getIp() {
return ip;
}
@XmlElement(name = "ip")
public void setIp(String ip) {
this.ip = ip;
}
public String getDnsName() {
return dnsName;
}
@XmlElement(name = "dnsName")
public void setDnsName(String dnsName) {
this.dnsName = dnsName;
}
}
但是当我用它来尝试反序列化包含 HandshakeInfo
元素的 Element
对象时,我得到了以下异常:
javax.xml.bind.UnmarshalException: unexpected element (uri:"urn:InitronSOAPService", local:"HandshakeInfo"). Expected elements are <{}HandshakeInfo>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:647)
...
然后我尝试将 , namespace="urn:InitronSOAPService"
添加到 class 中的所有元素和属性(在本例中为 none)注释。 (或者,或者,在 package-info.java 文件中使用 @XmlSchema
注释。)这适用于反序列化该名称空间中的该元素。
但是当我尝试使用 class 序列化到不同的命名空间时,我(并非完全出乎意料)得到了这样的东西:
<SomeMessage xmlns="urn:differentNamespace">
<ns5:HandshakeInfo xmlns:ns5="urn:InitronSOAPService">
<ns5:dnsName>foo.bar</ns5:dnsName>
<ns5:ip>1.2.3.4</ns5:ip>
<ns5:id>TheId</ns5:id>
<ns5:key>SomeKey</ns5:key>
<ns5:version>1.0</ns5:version>
</ns5:HandshakeInfo>
</SomeMessage>
那不是我想要的。我希望序列化的东西成为 urn:differentNamespace
.
的一部分
那么有没有办法在多个名称空间中使用相同的 JAXB class?或者我是否坚持必须拥有多个 classes 的副本,每个副本都被注释为在适当的命名空间中?
我见过一些使用过滤器等的技巧,但这些技巧似乎假设 XML 正在从流或文件中读取或写入流或文件。同样,对于解组,我正在使用 org.w3c.dom.Element
个对象,对于编组,我正在使用 SOAPBody
个对象。
我看到以下选项:
- 使用 MOXy XML Bindings 并将映射从注释移到 XML 资源中。然后,您可以为不同的命名空间定义和加载不同的资源。
- 在编组后 unmarshalling/postprocess 之前,使用 XSLT 预处理 XML。重新映射名称空间在 XSLT 中是一项微不足道的任务。
- 为 JAXB RI 使用自定义
AnnotationReader
到从注释读取的 "fake" 命名空间。你只需要调整从包中读取的命名空间,应该不会太难。
AnnotationReader
解决方案有点 "hacky",也将您与 JAXB RI 联系起来。 XML 绑定将要求您以 XML 形式重写注释,并将您绑定到 MOXy(我认为)。 XSLT 非常优雅,但会使处理速度变慢。而且您必须使用 XSLT 侵入处理链。
所有选项都有利有弊,您必须根据具体情况仔细考虑。
注意: 这是 Java 7. 此外,我没有使用 JAXB 从模式生成任何内容。我 only/merely 想使用 JAXB 反序列化现有 SOAP 消息的片段。所以 JAXB bean 是 "hand-written".
我正在尝试使用 JAXB 反序列化以下 XML。我没有 可以访问它作为字符串。相反,我将其作为 org.w3c.dom.Element
对象获取:
<SynchInfo xmlns="urn:InitronSOAPService">
<HandshakeInfo>
<dnsName>foo.bar</dnsName>
<ip>1.2.3.4</ip>
<id>TheId</id>
<key>SomeKey</key>
<version>1.0</version>
</HandshakeInfo>
</SynchInfo>
但我还想将 HandshakeInfo
个实例编组到一个 SOAPBody
中,它是属于 不同命名空间 .[=26 的消息的一部分=]
我首先尝试写一个 HandshakeInfo
class 完全没有提到命名空间:
@XmlRootElement(name = "HandshakeInfo")
@XmlAccessorType(XmlAccessType.NONE)
final private static class HandshakeInfo
{
private String version;
private String id;
private String key;
private String ip;
private String dnsName;
public String getVersion() {
return version;
}
@XmlElement(name = "version")
public void setVersion(String version) {
this.version = version;
}
public String getId() {
return id;
}
@XmlElement(name = "id")
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
@XmlElement(name = "key")
public void setKey(String key) {
this.key = key;
}
public String getIp() {
return ip;
}
@XmlElement(name = "ip")
public void setIp(String ip) {
this.ip = ip;
}
public String getDnsName() {
return dnsName;
}
@XmlElement(name = "dnsName")
public void setDnsName(String dnsName) {
this.dnsName = dnsName;
}
}
但是当我用它来尝试反序列化包含 HandshakeInfo
元素的 Element
对象时,我得到了以下异常:
javax.xml.bind.UnmarshalException: unexpected element (uri:"urn:InitronSOAPService", local:"HandshakeInfo"). Expected elements are <{}HandshakeInfo>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:647)
...
然后我尝试将 , namespace="urn:InitronSOAPService"
添加到 class 中的所有元素和属性(在本例中为 none)注释。 (或者,或者,在 package-info.java 文件中使用 @XmlSchema
注释。)这适用于反序列化该名称空间中的该元素。
但是当我尝试使用 class 序列化到不同的命名空间时,我(并非完全出乎意料)得到了这样的东西:
<SomeMessage xmlns="urn:differentNamespace">
<ns5:HandshakeInfo xmlns:ns5="urn:InitronSOAPService">
<ns5:dnsName>foo.bar</ns5:dnsName>
<ns5:ip>1.2.3.4</ns5:ip>
<ns5:id>TheId</ns5:id>
<ns5:key>SomeKey</ns5:key>
<ns5:version>1.0</ns5:version>
</ns5:HandshakeInfo>
</SomeMessage>
那不是我想要的。我希望序列化的东西成为 urn:differentNamespace
.
那么有没有办法在多个名称空间中使用相同的 JAXB class?或者我是否坚持必须拥有多个 classes 的副本,每个副本都被注释为在适当的命名空间中?
我见过一些使用过滤器等的技巧,但这些技巧似乎假设 XML 正在从流或文件中读取或写入流或文件。同样,对于解组,我正在使用 org.w3c.dom.Element
个对象,对于编组,我正在使用 SOAPBody
个对象。
我看到以下选项:
- 使用 MOXy XML Bindings 并将映射从注释移到 XML 资源中。然后,您可以为不同的命名空间定义和加载不同的资源。
- 在编组后 unmarshalling/postprocess 之前,使用 XSLT 预处理 XML。重新映射名称空间在 XSLT 中是一项微不足道的任务。
- 为 JAXB RI 使用自定义
AnnotationReader
到从注释读取的 "fake" 命名空间。你只需要调整从包中读取的命名空间,应该不会太难。
AnnotationReader
解决方案有点 "hacky",也将您与 JAXB RI 联系起来。 XML 绑定将要求您以 XML 形式重写注释,并将您绑定到 MOXy(我认为)。 XSLT 非常优雅,但会使处理速度变慢。而且您必须使用 XSLT 侵入处理链。
所有选项都有利有弊,您必须根据具体情况仔细考虑。