【问题标题】:How to override 'org.apache.cxf.stax.maxChildElements' property value inside a TomEE container?如何覆盖 TomEE 容器内的“org.apache.cxf.stax.maxChildElements”属性值?
【发布时间】:2017-12-22 23:17:21
【问题描述】:

我有一个纯粹通过在 TomEE 7 环境中运行的注释配置的 JAX-WS Web 服务端点。基本上,被调用的方法必须返回图形数据结构中包含的所有节点名称的List<String>。此类请求的响应可以包含更多的感谢 50k 元素。

使用 CXF 2.6.x 时效果很好。但是,当我在 CXF 3.x(捆绑在 TomEE 7.x 中)下调用 WS-method 时,服务器端会抛出以下异常:

org.apache.cxf.interceptor.Fault: Unmarshalling Error: Maximum Number of Child Elements limit (50000) Exceeded 
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:906)
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:712)
    at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:179)
    at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:109)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:801)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1680)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1559)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1356)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:653)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:423)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:324)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:277)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:139)
    at com.sun.proxy.$Proxy51.getAllNodeNames(Unknown Source)
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
[javax.xml.stream.XMLStreamException: Maximum Number of Child Elements limit (50000) Exceeded]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:485)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:417)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:394)
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.doUnmarshal(JAXBEncoderDecoder.java:855)
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.access$100(JAXBEncoderDecoder.java:102)
    at org.apache.cxf.jaxb.JAXBEncoderDecoder$2.run(JAXBEncoderDecoder.java:894)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:892)
    ... 21 more
Caused by: javax.xml.stream.XMLStreamException: Maximum Number of Child Elements limit (50000) Exceeded
    at com.ctc.wstx.sr.InputElementStack.push(InputElementStack.java:340)
    at com.ctc.wstx.sr.BasicStreamReader.handleStartElem(BasicStreamReader.java:2951)
    at com.ctc.wstx.sr.BasicStreamReader.nextFromTree(BasicStreamReader.java:2839)
    at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1073)
    at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:196)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:415)
    ... 27 more
Error: Maximum Number of Child Elements limit (50000) Exceeded 

到目前为止,我已经阅读了有关此问题的官方 CXF documentation,查看了 HowTo at the TomEE 网站并阅读了论坛中许多相关但较旧的帖子。

我尝试通过 Web 服务的 WEB-INF 文件夹中的 openejb-jar.xml 设置属性 - 正如 TomEE 文档所建议的那样:

<?xml version="1.0" encoding="UTF-8"?>
<openejb-jar>
 <ejb-deployment ejb-name="MyWebService">
   <properties>
     org.apache.cxf.stax.maxChildElements = 100000
   </properties>
 </ejb-deployment>
</openejb-jar>

我还尝试使用较短的属性cxf.stax.maxChildElements 来检查这是否会被接受,但没有成功。

为了测试/调试,我通过 tomee-maven-plugin 启动 TomEE 实例,因此,我尝试将 maxChildElement 属性设置为环境属性,如下所示:

<plugin>
    <groupId>org.apache.tomee.maven</groupId>
    <artifactId>tomee-maven-plugin</artifactId>
    <version>${tomee.plugin.version}</version>
    <configuration>
        <tomeeVersion>${tomee.version}</tomeeVersion>
        <tomeeClassifier>plus</tomeeClassifier>
        <debug>false</debug>
        <tomeeHttpPort>8181</tomeeHttpPort>
        <debugPort>5005</debugPort>
        <args>-Dfoo=bar</args>
        <skipCurrentProject>true</skipCurrentProject>
        <webapps>
            <webapp>my.ws:${webservice.artifact.name}:${webservice.artifact.version}?name=ws-endpoint</webapp>
        </webapps>
        <libs>
            <!-- Third party libraries needed in the global lib folder of TomEE -->
            <lib>log4j:log4j:${log4j.version}</lib>
        </libs>
        <systemVariables>
            <!--
                special property needed to allow for more childElements in StAX Parser
            -->
            <org.apache.cxf.stax.maxChildElement>100000</org.apache.cxf.stax.maxChildElement>
        </systemVariables>
    </configuration>
</plugin>

遗憾的是,它对 CXF/StAX (Woodstox) 的运行时配置没有影响。

问题

我们如何通过openejb-jar.xml 中的配置或作为TomEE 启动时的外部属性来覆盖maxChildElements 属性。

【问题讨论】:

    标签: xml-parsing cxf apache-tomee stax tomee-7


    【解决方案1】:

    最后,我在Romain Manni-Bucau 的帮助下完成了它(感谢他为我指明了正确的方向)。然而,他最初的答案并不是最终的解决方案。因此,我在这里给出工作配置。

    1.) 将以下openejb-jar.xml 放入WEB-INF 文件夹:

    <?xml version="1.0" encoding="UTF-8"?>
    <openejb-jar>
        <ejb-deployment ejb-name="MyWebService">
            <properties>
                cxf.jaxws.properties = cxfConfig
            </properties>
        </ejb-deployment>
    </openejb-jar>
    

    2.) 再次通过WEB-INF 提供一个新的(或添加到现有的)resources.xml 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <resources>
        <Service id="cxfConfig" class-name="org.apache.openejb.config.sys.MapFactory" factory-name="create">
            org.apache.cxf.stax.maxChildElements = 100000
        </Service>
    </resources>
    

    请注意通过 ID 为 cxfConfigMapFactory 对象的配置链接。

    3.) 配置 JAX-WS 客户端以设置相应的属性。例如,给定一个 Spring 客户端,可以这样配置:

    <bean id="wsClientProxy" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
        <property name="serviceClass" value="com.acme.ws.jaxb.MyWebservice"/>
        <property name="address" value="${ws.endpoint.url}"/>
        <property name="properties">
            <map>
                <entry key="org.apache.cxf.stax.maxChildElements" value="100000" />
            </map>
        </property>
    </bean>
    

    一般来说,这对于尝试设置XML section of the CXF security guideline 中列出的其他与 CXF 相关的属性的人可能也很有用,特别是增加或减少保守的默认值。

    我在 TomEE 7.0.3 和 8.0.9 环境下成功测试了上述配置步骤,但这也应该可以可靠地用于所有 7.0.x 和 8.0.x 版本。

    对于其他用例,this blog post by Romain 可能也值得一读,因为它很好地涵盖了基本配置概念。

    希望这对其他人有所帮助。

    【讨论】:

      【解决方案2】:

      你可以试试 -Dorg.apache.cxf.stax.maxChildElements=100000 它也应该工作

      【讨论】:

        【解决方案3】:

        我认为您需要使用 java.util.Properties 类型(类名)的 Service 和里面的属性定义一个 resources.xml:

        1. openejb-jar.xml 会得到这个属性:

          cxf.jaxws.properties = cxfConfig

        2. resources.xml 会得到

          org.apache.cxf.stax.maxChildElements = 1

        此测试以编程方式进行:https://github.com/apache/tomee/blob/master/server/openejb-cxf/src/test/java/org/apache/openejb/server/cxf/MaxChildTest.java

        【讨论】:

        • 这导致org.apache.openejb.config.NoSuchProviderException: Cannot determine a provider for Resource(id=ws-endpoint/cxfConfig, type=java.util.Properties, provider=null). 可能的有效配置可能是: ...
        猜你喜欢
        • 1970-01-01
        • 2021-01-19
        • 2020-12-23
        • 2019-04-04
        • 2022-01-08
        • 1970-01-01
        • 2011-11-06
        • 1970-01-01
        • 2015-01-08
        相关资源
        最近更新 更多