JAXB - 抽象 类 的解组(InstantiationException)
JAXB - Unmarshalling of abstract classes (InstantiationException)
我知道,这个问题似乎与这个问题重复:InstantiationException during JAXB Unmarshalling (abstract base class, with @XmlSeeAlso concrete sub class)
然而,它略有不同:我们使用 maven-jaxb2-plugin
从 xsd 文件生成我们的 Java-类。你可以找到他们 here.
在我们的 pom 中,我们使用以下配置(我们在 2.3.1 版本中使用 jaxb-api):
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<id>schema2-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<args>
<arg>-Xnamespace-prefix</arg>
</args>
<useActiveProxyAsHttpproxy>true</useActiveProxyAsHttpproxy>
<proxyHost>your.host</proxyHost>
<proxyPort>your.port</proxyPort>
<strict>false</strict>
<encoding>UTF-8</encoding>
<catalog>src/main/resources/xsd/xbau/v22/catalog.cat</catalog>
<schemaDirectory>src/main/resources/xsd/xbau/v22</schemaDirectory>
<schemaIncludes>
<include>*.xsd</include>
</schemaIncludes>
<bindingDirectory>src/main/resources/xsd/xbau/v22/xjb</bindingDirectory>
<bindingIncludes>
<bindingInclude>externalBindings.xjb</bindingInclude>
</bindingIncludes>
<generatePackage>our.generated.package.xbau.v22</generatePackage>
<generateDirectory>${project.build.directory}/generated-sources/xbau/v22</generateDirectory>
</configuration>
</execution>
</executions>
</plugin>
JAXB 正在生成以下 类:
Nachrichtenkopf.G2G2(子类):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Nachrichtenkopf.G2G")
public class NachrichtenkopfG2G2
extends NachrichtenkopfG2G
{
}
Nachrichtenkopf.G2G(超类):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Nachrichtenkopf.G2G", namespace = "http://www.osci.de/xinneres/basisnachricht/4", propOrder = {
"identifikationNachricht",
"leser",
"autor"
})
@XmlSeeAlso({
NachrichtenkopfG2G2 .class
})
public abstract class NachrichtenkopfG2G {
@XmlElement(name = "identifikation.nachricht", namespace = "", required = true)
protected IdentifikationNachricht2 identifikationNachricht;
@XmlElement(namespace = "", required = true)
protected Behoerde leser;
@XmlElement(namespace = "", required = true)
protected BehoerdeErreichbar autor;
...
}
现在,如果我们收到一个 XML 没有 xsi 类型(见下文)的“Nachrichtenkopf”,我们会收到一个 InstantiationException,因为由于缺少类型,解组器无法创建具体实例信息:
<?xml version="1.0" encoding="utf-8"?>
<xbau:beteiligung.aufforderung.0300 xmlns="http://www.xleitstelle.de/xbau/2/2/" produkt="Produkt" produkthersteller="Hersteller" produktversion="Version1" standard="XBau" version="2.2" xmlns:xbau="http://www.xleitstelle.de/xbau/2/2">
<nachrichtenkopf xmlns=""> <!-- Missing Type information: xsi:type="xbau:Nachrichtenkopf.G2G" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-->
...
</nachrichtenkopf>
...
基本上,我有两个问题:
- 有没有办法告诉 Unmarshaller 如何在没有上述类型信息的情况下解组消息?
- xsi-type-information 是强制性的吗?或者换句话说:根据方案 (xsds),上面的 XML 是否有效?
为了完整起见,externalBindings.xjb
的内容
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net"
xmlns:namespace="http://jaxb2-commons.dev.java.net/namespace-prefix"
jaxb:version="2.1">
<!-- Bemerkung: Die Schemagenerierung hat hier dazu geführt, dass es in der Factory
zwei gleichnamige Methoden gibt, daher werden die Methoden hier explizit benannt -->
<jaxb:globalBindings fixedAttributeAsConstantProperty="true"/>
<jaxb:bindings schemaLocation="http://www.w3.org/1999/xlink.xsd">
<jaxb:bindings node="xs:group[@name='arcModel']">
<jaxb:bindings node=".//xs:element[@ref='xlink:title']">
<jaxb:property name="arcModelTitle"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings node="xs:group[@name='locatorModel']">
<jaxb:bindings node=".//xs:element[@ref='xlink:title']">
<jaxb:property name="locatorModelTitle"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings node="xs:element[@name='arc']">
<jaxb:factoryMethod name="arc42"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="../xbau-baukasten.xsd">
<jaxb:bindings node="xs:complexType[@name='Nachrichtenkopf.G2G']">
<jaxb:class name="NachrichtenkopfG2G2"/>
</jaxb:bindings>
<jaxb:bindings>
<namespace:prefix name="xbau" />
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/basisnachricht/4/xinneres-basisnachricht.xsd">
<jaxb:bindings node="xs:complexType[@name='Nachricht.G2G']">
<jaxb:class name="NachrichtG2G2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/basisnachricht/4/xinneres-basisnachricht.xsd">
<jaxb:bindings node="xs:complexType[@name='Identifikation.Nachricht']">
<jaxb:class name="IdentifikationNachricht2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/kommunikation/3/xinneres-kommunikation.xsd">
<jaxb:bindings node="xs:complexType[@name='Code.Erreichbarkeit']">
<jaxb:class name="CodeErreichbarkeit2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/kommunikation/3/xinneres-kommunikation.xsd">
<jaxb:bindings node="xs:complexType[@name='Kommunikation']">
<jaxb:class name="Kommunikation2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.w3.org/1999/xlink.xsd">
<jaxb:bindings node="xs:complexType[@name='arcType']">
<jaxb:class name="ArcType2"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
使用 catalog-file 解决了问题。 catalog.cat-file(查看我原来问题中的第一个 code-block)包含一个条目,建议模式解析器在我的本地 [=23= 中查找导致问题的模式] 而不是在网上查找。如果你有兴趣在xsd-parsing(jaxb - how to map xsd files to URL to find them)的上下文中将在线资源重写为本地资源,你可以看看这个post。
这样我就可以更改现在驻留在我的 src/main/resources
文件夹中的方案。有问题的方案是 http://www.osci.de/xinneres/basisnachricht/4/xinneres-basisnachricht.xsd。我将 name="Nachrichtenkopf.G2G" abstract="true"
更改为 name="Nachrichtenkopf.G2G" abstract="false"
以便 class Nachrichtenkopf.G2G
不再是抽象的,因此可以实例化。
我知道,这个问题似乎与这个问题重复:InstantiationException during JAXB Unmarshalling (abstract base class, with @XmlSeeAlso concrete sub class)
然而,它略有不同:我们使用 maven-jaxb2-plugin
从 xsd 文件生成我们的 Java-类。你可以找到他们 here.
在我们的 pom 中,我们使用以下配置(我们在 2.3.1 版本中使用 jaxb-api):
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<id>schema2-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<args>
<arg>-Xnamespace-prefix</arg>
</args>
<useActiveProxyAsHttpproxy>true</useActiveProxyAsHttpproxy>
<proxyHost>your.host</proxyHost>
<proxyPort>your.port</proxyPort>
<strict>false</strict>
<encoding>UTF-8</encoding>
<catalog>src/main/resources/xsd/xbau/v22/catalog.cat</catalog>
<schemaDirectory>src/main/resources/xsd/xbau/v22</schemaDirectory>
<schemaIncludes>
<include>*.xsd</include>
</schemaIncludes>
<bindingDirectory>src/main/resources/xsd/xbau/v22/xjb</bindingDirectory>
<bindingIncludes>
<bindingInclude>externalBindings.xjb</bindingInclude>
</bindingIncludes>
<generatePackage>our.generated.package.xbau.v22</generatePackage>
<generateDirectory>${project.build.directory}/generated-sources/xbau/v22</generateDirectory>
</configuration>
</execution>
</executions>
</plugin>
JAXB 正在生成以下 类:
Nachrichtenkopf.G2G2(子类):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Nachrichtenkopf.G2G")
public class NachrichtenkopfG2G2
extends NachrichtenkopfG2G
{
}
Nachrichtenkopf.G2G(超类):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Nachrichtenkopf.G2G", namespace = "http://www.osci.de/xinneres/basisnachricht/4", propOrder = {
"identifikationNachricht",
"leser",
"autor"
})
@XmlSeeAlso({
NachrichtenkopfG2G2 .class
})
public abstract class NachrichtenkopfG2G {
@XmlElement(name = "identifikation.nachricht", namespace = "", required = true)
protected IdentifikationNachricht2 identifikationNachricht;
@XmlElement(namespace = "", required = true)
protected Behoerde leser;
@XmlElement(namespace = "", required = true)
protected BehoerdeErreichbar autor;
...
}
现在,如果我们收到一个 XML 没有 xsi 类型(见下文)的“Nachrichtenkopf”,我们会收到一个 InstantiationException,因为由于缺少类型,解组器无法创建具体实例信息:
<?xml version="1.0" encoding="utf-8"?>
<xbau:beteiligung.aufforderung.0300 xmlns="http://www.xleitstelle.de/xbau/2/2/" produkt="Produkt" produkthersteller="Hersteller" produktversion="Version1" standard="XBau" version="2.2" xmlns:xbau="http://www.xleitstelle.de/xbau/2/2">
<nachrichtenkopf xmlns=""> <!-- Missing Type information: xsi:type="xbau:Nachrichtenkopf.G2G" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-->
...
</nachrichtenkopf>
...
基本上,我有两个问题:
- 有没有办法告诉 Unmarshaller 如何在没有上述类型信息的情况下解组消息?
- xsi-type-information 是强制性的吗?或者换句话说:根据方案 (xsds),上面的 XML 是否有效?
为了完整起见,externalBindings.xjb
的内容<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net"
xmlns:namespace="http://jaxb2-commons.dev.java.net/namespace-prefix"
jaxb:version="2.1">
<!-- Bemerkung: Die Schemagenerierung hat hier dazu geführt, dass es in der Factory
zwei gleichnamige Methoden gibt, daher werden die Methoden hier explizit benannt -->
<jaxb:globalBindings fixedAttributeAsConstantProperty="true"/>
<jaxb:bindings schemaLocation="http://www.w3.org/1999/xlink.xsd">
<jaxb:bindings node="xs:group[@name='arcModel']">
<jaxb:bindings node=".//xs:element[@ref='xlink:title']">
<jaxb:property name="arcModelTitle"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings node="xs:group[@name='locatorModel']">
<jaxb:bindings node=".//xs:element[@ref='xlink:title']">
<jaxb:property name="locatorModelTitle"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings node="xs:element[@name='arc']">
<jaxb:factoryMethod name="arc42"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="../xbau-baukasten.xsd">
<jaxb:bindings node="xs:complexType[@name='Nachrichtenkopf.G2G']">
<jaxb:class name="NachrichtenkopfG2G2"/>
</jaxb:bindings>
<jaxb:bindings>
<namespace:prefix name="xbau" />
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/basisnachricht/4/xinneres-basisnachricht.xsd">
<jaxb:bindings node="xs:complexType[@name='Nachricht.G2G']">
<jaxb:class name="NachrichtG2G2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/basisnachricht/4/xinneres-basisnachricht.xsd">
<jaxb:bindings node="xs:complexType[@name='Identifikation.Nachricht']">
<jaxb:class name="IdentifikationNachricht2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/kommunikation/3/xinneres-kommunikation.xsd">
<jaxb:bindings node="xs:complexType[@name='Code.Erreichbarkeit']">
<jaxb:class name="CodeErreichbarkeit2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.osci.de/xinneres/kommunikation/3/xinneres-kommunikation.xsd">
<jaxb:bindings node="xs:complexType[@name='Kommunikation']">
<jaxb:class name="Kommunikation2"/>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="http://www.w3.org/1999/xlink.xsd">
<jaxb:bindings node="xs:complexType[@name='arcType']">
<jaxb:class name="ArcType2"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
使用 catalog-file 解决了问题。 catalog.cat-file(查看我原来问题中的第一个 code-block)包含一个条目,建议模式解析器在我的本地 [=23= 中查找导致问题的模式] 而不是在网上查找。如果你有兴趣在xsd-parsing(jaxb - how to map xsd files to URL to find them)的上下文中将在线资源重写为本地资源,你可以看看这个post。
这样我就可以更改现在驻留在我的 src/main/resources
文件夹中的方案。有问题的方案是 http://www.osci.de/xinneres/basisnachricht/4/xinneres-basisnachricht.xsd。我将 name="Nachrichtenkopf.G2G" abstract="true"
更改为 name="Nachrichtenkopf.G2G" abstract="false"
以便 class Nachrichtenkopf.G2G
不再是抽象的,因此可以实例化。