如何覆盖 TomEE 容器内的 'org.apache.cxf.stax.maxChildElements' 属性 值?
How to override 'org.apache.cxf.stax.maxChildElements' property value inside a TomEE container?
我有一个在 TomEE 7 环境中完全通过注释 运行 配置的 JAX-WS Web 服务端点。基本上,被调用的方法必须 return 包含在图形数据结构中的所有节点名称的 List<String>
。这样一个请求的响应可以包含更多的thank 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.access0(JAXBEncoderDecoder.java:102)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.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 on this issue, checked a HowTo at the TomEE 网站并在论坛中阅读了许多相关但较旧的帖子。
我尝试通过 webservice 的 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
来检查这是否会被接受,但没有成功。
对于testing/debugging,我通过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
属性。
我认为您需要使用类型为 (class-name) java.util.Properties 的服务定义 resources.xml 以及其中的属性:
openejb-jar.xml 会得到这个 属性:
cxf.jaxws.properties = cxfConfig
resources.xml 会得到
org.apache.cxf.stax.maxChildElements = 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 为 cxfConfig
的 MapFactory
对象配置 link。
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 可能也值得一读,因为它很好地涵盖了基本的配置概念。
希望这对其他人有帮助。
你可以试试
-Dorg.apache.cxf.stax.maxChildElements=100000
它也应该有效
我有一个在 TomEE 7 环境中完全通过注释 运行 配置的 JAX-WS Web 服务端点。基本上,被调用的方法必须 return 包含在图形数据结构中的所有节点名称的 List<String>
。这样一个请求的响应可以包含更多的thank 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.access0(JAXBEncoderDecoder.java:102)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.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 on this issue, checked a HowTo at the TomEE 网站并在论坛中阅读了许多相关但较旧的帖子。
我尝试通过 webservice 的 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
来检查这是否会被接受,但没有成功。
对于testing/debugging,我通过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
属性。
我认为您需要使用类型为 (class-name) java.util.Properties 的服务定义 resources.xml 以及其中的属性:
openejb-jar.xml 会得到这个 属性:
cxf.jaxws.properties = cxfConfig
resources.xml 会得到
org.apache.cxf.stax.maxChildElements = 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 为 cxfConfig
的 MapFactory
对象配置 link。
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 可能也值得一读,因为它很好地涵盖了基本的配置概念。
希望这对其他人有帮助。
你可以试试 -Dorg.apache.cxf.stax.maxChildElements=100000 它也应该有效