StaxEventItemReader中的Jaxb2Marshaller导致UnmarshalException

时间:2014-10-20 18:51:34

标签: jaxb spring-batch stax

所以我试图解析一个xml并将其解组成一个程序。这是示例xml:

<MaintenanceTransaction:provideCommunicationEvents_BatchRequest
        xmlns:MaintenanceTransaction="http://www.pwx.com/Interface/CRS/MaintenanceTransaction_v02"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <MaintenanceTransaction:maintenanceTransaction>
        <MaintenanceTransaction:eventInitiatedBy>
            <MaintenanceTransaction:identifier>FINACLE</MaintenanceTransaction:identifier>
        </MaintenanceTransaction:eventInitiatedBy>
        <MaintenanceTransaction:transactionDate>2014-06-21T19:00:32.356+01:00</MaintenanceTransaction:transactionDate>
        <MaintenanceTransaction:maintenanceTransactionType>PRE-NOTIFICATION
        </MaintenanceTransaction:maintenanceTransactionType>
        <MaintenanceTransaction:maintenanceEntries>
            <MaintenanceTransaction:hasNewValues xsi:type="MaintenanceTransaction:DepositArrangement">
                <MaintenanceTransaction:enterpriseId xsi:type="MaintenanceTransaction:ArrangementIdentifier">
                    <MaintenanceTransaction:identifier>222000000322</MaintenanceTransaction:identifier>
                    <MaintenanceTransaction:enterpriseIdType>Term Deposit</MaintenanceTransaction:enterpriseIdType>
                </MaintenanceTransaction:enterpriseId>
                <MaintenanceTransaction:maturityDate>2014-10-08</MaintenanceTransaction:maturityDate>
            </MaintenanceTransaction:hasNewValues>
        </MaintenanceTransaction:maintenanceEntries>
    </MaintenanceTransaction:maintenanceTransaction>
</MaintenanceTransaction:provideCommunicationEvents_BatchRequest>

xsd定义为:

<xsd:schema xmlns:MaintenanceTransaction="http://www.pwx.com/Interface/CRS/MaintenanceTransaction_v02" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.pwx.com/Interface/CRS/MaintenanceTransaction_v02" elementFormDefault="qualified" attributeFormDefault="qualified">
    <xsd:include schemaLocation="./commonIFWxsd/IFWXML.xsd" />
    <xsd:include schemaLocation="./commonIFWxsd/Event.xsd" />
    <xsd:include schemaLocation="./commonIFWxsd/Arrangement.xsd" />
    <!-- end of TYPES REQUIRED FOR PARAMETERS -->
    <xsd:complexType name="provideCommunicationEvents_BatchRequest">
        <xsd:sequence>
            <xsd:element name="maintenanceTransaction" type="MaintenanceTransaction:MaintenanceTransaction" maxOccurs="unbounded" />
        </xsd:sequence>
    </xsd:complexType>
    <!-- TYPES REQUIRED FOR PARAMETERS -->
    <xsd:element name="provideCommunicationEvents_BatchRequest" type="MaintenanceTransaction:provideCommunicationEvents_BatchRequest" />
</xsd:schema>

使用我的StaxEventItemReader和Jaxb2Marshaller的以下设置:

<bean id="uploadEventMessageReader" parent="abstractUploadEventMessageReader" scope="step">
    <property name="resource" value="file:#{jobExecutionContext['fileToProcess']}"/>
    <property name="fragmentRootElementName" value="maintenanceTransaction"/>
    <property name="unmarshaller" ref="maintenanceTransactionUnmarshaller"/>
</bean>

<bean id="maintenanceTransactionUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" scope="step">
    <property name="classesToBeBound">
        <list>
            <value>com.pwx.crs.informationcollection.ifw.process.model.mt.MaintenanceTransaction</value>
        </list>
    </property>
</bean>

然而问题是我得到以下异常。

 * [javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.pwx.com/Interface/CRS/MaintenanceTransaction_v02", local:"maintenanceTransaction"). Expected elements are (none)] on step uploadEventMessages, with message: uploadEventMessagesStep. 
 * --stacktrace:com.pwx.crs.frwk.exp.technical.CRS2UnexpectedBatchException: An unexpected exception occurred in batch job JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException

知道这是关于什么的吗?

当我稍微更改输入xml的maintenanceTransaction开始标记时,如下所示:

<MaintenanceTransaction:maintenanceTransaction xsi:type="MaintenanceTransaction:MaintenanceTransaction">

确实有效。但这不是一个解决方案,因为客户端不会像这样提供输入xml。那么为什么会出现错误呢?确定维护事务处理属于哪个类似乎存在问题。

还尝试了关于marshaller bean定义的不同方法:

<bean id="maintenanceTransactionUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" scope="step">
    <property name="contextPath" value="com.pwx.crs.informationcollection.ifw.process.model.mt"/>
</bean>

<bean id="maintenanceTransactionUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" scope="step">
    <property name="classesToBeBound">
        <list>
            <value>com.pwx.crs.informationcollection.ifw.process.model.mt.ObjectFactory</value>
        </list>
    </property>
</bean>

两者的结果与第一个错误

相同且相似

javax.xml.bind.UnmarshalException:意外元素(uri:“http://www.pwx.com/Interface/CRS/MaintenanceTransaction_v02”,local:“maintenanceTransaction”)。预期的元素是&lt; {{{}}} AccessTokenLifecycleStatus&gt; ...这里是包中的整个类列表。

但xml对xsd完全有效,因为这是事先完成的。想法,建议,......我可以试试吗?

3 个答案:

答案 0 :(得分:5)

因此,在研究完代码和调试以及更多的工作后,我最终得到了一些有用的东西。我不知道为什么,因为这是猜测,但它确实有效。

<bean id="maintenanceTransactionUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>com.pwx.crs.informationcollection.ifw.process.model.mt.MaintenanceTransaction</value>
        </list>
    </property>
    <property name="mappedClass" value="com.pwx.crs.informationcollection.ifw.process.model.mt.MaintenanceTransaction"/>
</bean>

正如您所看到的那样,没有必要将ObjectFactory用作classesToBeBound(但必须注意它本来会有效,但在我看来这更具可读性)。真正修复它的是添加mappedClass。

从调试时我在代码中看到的内容(我无法检查代码f UnmarshallingImpl,因为这是rt.jar的一部分,即使它是jre的一部分也不公开...)classesToBeBound参数用于为unmarshaller创建jaxbContext,mappedClass作为expectedType传递给此unmarshaller。但是当没有提供并且ObjectFactory用作参数时,错误清楚地显示了预期类的列表,并且存在适用的类...可能是unmarshaller中的错误,也许是我不理解的东西。但我的根本问题已经解决了。

答案 1 :(得分:5)

这是我的理论。

mappedClass实际执行的操作是将解组方法从unmarshaller.unmarshal(source)切换为unmarshaller.unmarshal(source, this.mappedClass)。这称为&#34;部分解组&#34;,即无论元素名称如何,您都可以从某个元素解组已知类。

所以,正如你所说,这对你有用。它没有mappedClass。这意味着您缺少根元素的元素声明。这也很好地与您报告的错误相符:

javax.xml.bind.UnmarshalException: unexpected element
(uri:"http://www.pwx.com/Interface/CRS/MaintenanceTransaction_v02",
local:"maintenanceTransaction"). Expected elements are (none)

其中说的基本相同。

这也是正确的。由于您的架构未声明maintenanceTransaction的全局元素,仅适用于provideCommunicationEvents_BatchRequest

所以,基本上你是在解组错误的元素。并且由于您的架构没有声明,因此失败。但是如果你确切地指定你想要的类型(从而提供声明&#34;明确地&#34;),那么它就可以了。

接下来,问题是,为什么要解组错误的元素。我猜这是因为你有

<property name="fragmentRootElementName" value="maintenanceTransaction"/>

这可能指向unmarshaller使用maintenanceTransaction元素作为根元素。所以unmarshaller应用于错误的元素。

使用contextPath,添加更多绑定类等没有帮助,因为它们都没有添加maintenanceTransaction的元素声明。

现在,如何解决这个问题。我看到以下选项:

  • 为您的架构添加maintenanceTransaction的全局元素
  • (OR)自定义您的架构,为@XmlRootElement
  • 生成额外的MaintenanceTransaction
  • (或)不要使用fragmentRootElementName,unmarshal provideCommunicationEvents_BatchRequest
  • (或)保持原样mappedClass

如果您在此处理特定案例,即maintenanceTransaction,那么我将使用fragmentRootElementName / mappedClass组合。就像你现在一样。

答案 2 :(得分:0)

在从XML Schema生成的模型上创建JAXBContext时,您应该执行以下操作之一以获取所有必需的元数据:

选项#1 - 在生成的ObjectFactory

上创建它
<bean id="maintenanceTransactionUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" scope="step">
    <property name="classesToBeBound">
        <list>
            <value>com.pwx.crs.informationcollection.ifw.process.model.mt.ObjectFactory</value>
        </list>
    </property>
</bean>

选项#2 - 在生成模型的包名称上创建

<bean id="maintenanceTransactionUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" scope="step">
    <property name="contextPath" value="com.pwx.crs.informationcollection.ifw.process.model.mt"/>
</bean>