This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/3.6.x-fixes by this push:
new 0ce3df36ab CXF-9007: NullPointerException in
XMLStreamDataWriter.writeNode (#1861)
0ce3df36ab is described below
commit 0ce3df36abc2a53f4e30ea8b958b825ac8f6a6a7
Author: Andriy Redko <[email protected]>
AuthorDate: Tue Jun 18 17:21:25 2024 -0400
CXF-9007: NullPointerException in XMLStreamDataWriter.writeNode (#1861)
---
.../main/java/org/apache/cxf/helpers/DOMUtils.java | 5 +-
systests/transport-hc5/pom.xml | 10 ++
.../systest/hc5/jaxws/JAXWSAsyncClientTest.java | 105 ++++++++++++-
.../org/apache/cxf/systest/hc5/jaxws/greeting.wsdl | 166 +++++++++++++++++++++
4 files changed, 284 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
b/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
index 37bde6779d..c781719f01 100644
--- a/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
+++ b/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
@@ -790,7 +790,10 @@ public final class DOMUtils {
//java9 plus hack
Field f = GET_DOCUMENT_FRAGMENT_FIELDS.get(fragment.getClass());
if (f != null) {
- return ReflectionUtil.accessDeclaredField(f, fragment,
DocumentFragment.class);
+ final DocumentFragment inner =
ReflectionUtil.accessDeclaredField(f, fragment, DocumentFragment.class);
+ if (inner != null) {
+ return inner;
+ }
}
}
return fragment;
diff --git a/systests/transport-hc5/pom.xml b/systests/transport-hc5/pom.xml
index 91471c40d4..540c568afb 100644
--- a/systests/transport-hc5/pom.xml
+++ b/systests/transport-hc5/pom.xml
@@ -249,5 +249,15 @@
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>jakarta.xml.soap</groupId>
+ <artifactId>jakarta.xml.soap-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.messaging.saaj</groupId>
+ <artifactId>saaj-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
index 31d2579263..20133d67ae 100644
---
a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
+++
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
@@ -20,10 +20,31 @@
package org.apache.cxf.systest.hc5.jaxws;
import java.util.Random;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.xml.namespace.QName;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
import javax.jws.WebService;
+import javax.xml.ws.Dispatch;
import javax.xml.ws.Response;
+import javax.xml.ws.Service;
+import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;
import org.apache.cxf.endpoint.Client;
@@ -43,13 +64,15 @@ import org.junit.BeforeClass;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class JAXWSAsyncClientTest extends AbstractBusClientServerTestBase {
static final String PORT = allocatePort(Server.class);
-
+ static ScheduledExecutorService executor;
+
public static class Server extends AbstractBusTestServerBase {
protected void run() {
@@ -95,11 +118,18 @@ public class JAXWSAsyncClientTest extends
AbstractBusClientServerTestBase {
@BeforeClass
public static void startServers() throws Exception {
assertTrue("server did not launch correctly",
launchServer(Server.class, true));
+ executor = Executors.newScheduledThreadPool(5);
}
@AfterClass
public static void stopServers() throws Exception {
stopAllServers();
+ if (executor != null) {
+ executor.shutdown();
+ if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
+ executor.shutdownNow();
+ }
+ }
}
@Test
@@ -176,4 +206,77 @@ public class JAXWSAsyncClientTest extends
AbstractBusClientServerTestBase {
|| ex.getCause() instanceof
java.net.SocketTimeoutException);
}
}
+
+ /**
+ * Not 100% reproducible but used to sporadically fail with:
+ *
+ * java.util.concurrent.ExecutionException:
jakarta.xml.ws.soap.SOAPFaultException:
+ * Cannot invoke "org.w3c.dom.Node.getOwnerDocument()" because "nd" is
null
+ * at
java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
+ * at
java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073)
+ * at org.apache.cxf.endpoint.ClientCallback.get(ClientCallback.java:139)
+ * at
org.apache.cxf.jaxws.JaxwsResponseCallback.get(JaxwsResponseCallback.java:48)
+ * at
org.apache.cxf.systest.hc5.jaxws.JAXWSAsyncClientTest.testAsyncWsdl(JAXWSAsyncClientTest.java:193)
+ *
+ * @see https://issues.apache.org/jira/browse/CXF-9007
+ */
+ @Test
+ public void testAsyncWsdl() throws Exception {
+ final URL wsdlUrl =
getClass().getClassLoader().getResource("greeting.wsdl");
+
+ final Service service = Service.create(wsdlUrl, new
QName("http://apache.org/hello_world", "SOAPService"));
+
+ service.addPort(new QName("http://apache.org/hello_world", "Greeter"),
SOAPBinding.SOAP11HTTP_BINDING,
+ "http://localhost:" + PORT + "/SoapContext/GreeterPort");
+
+ final Dispatch<SOAPMessage> client = service.createDispatch(
+ new QName("http://apache.org/hello_world", "Greeter"),
+ SOAPMessage.class,
+ Service.Mode.MESSAGE
+ );
+
+ final List<Future<Response<SOAPMessage>>> tasks = new ArrayList<>();
+ for (int i = 0; i < 50; i++) {
+ tasks.add(executor.submit(() ->
client.invokeAsync(buildMessage())));
+ }
+
+ for (Future<Response<SOAPMessage>> task : tasks) {
+ final SOAPMessage result = task.get(5, TimeUnit.SECONDS).get();
+ verifyResult(result);
+ }
+ }
+
+ private static void verifyResult(SOAPMessage message) throws Exception {
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+
+ String output = null;
+ try (StringWriter writer = new StringWriter()) {
+ final DOMSource source = new
DOMSource(message.getSOAPBody().extractContentAsDocument());
+ transformer.transform(source, new StreamResult(writer));
+ output = writer.getBuffer().toString().replaceAll("\n|\r", "");
+ }
+
+ assertThat(output, containsString("HELLO"));
+ }
+
+ private static SOAPMessage buildMessage() throws SOAPException,
IOException {
+ String soapMessage =
+ "<soapenv:Envelope
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ + "<soapenv:Header/>"
+ + " <soapenv:Body>"
+ + " <ns2:greetMe
xmlns:ns2=\"http://cxf.apache.org/greeter_control/types\">"
+ + " <ns2:requestType>Hello</ns2:requestType>"
+ + " </ns2:greetMe>"
+ + " </soapenv:Body>"
+ + "</soapenv:Envelope>";
+
+ SOAPMessage message = null;
+ try (ByteArrayInputStream bis = new
ByteArrayInputStream(soapMessage.getBytes())) {
+ message = MessageFactory.newInstance().createMessage(null, bis);
+ message.saveChanges();
+ }
+
+ return message;
+ }
}
diff --git
a/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/jaxws/greeting.wsdl
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/jaxws/greeting.wsdl
new file mode 100644
index 0000000000..c12bdfe88a
--- /dev/null
+++
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/jaxws/greeting.wsdl
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://apache.org/hello_world"
xmlns:x1="http://apache.org/hello_world/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="HelloWorld"
targetNamespace="http://apache.org/hello_world">
+ <wsdl:types>
+ <schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://apache.org/hello_world/types"
targetNamespace="http://apache.org/hello_world/types"
elementFormDefault="qualified">
+ <simpleType name="MyStringType">
+ <restriction base="string">
+ <maxLength value="30"/>
+ </restriction>
+ </simpleType>
+ <element name="sayHi">
+ <complexType/>
+ </element>
+ <element name="sayHiResponse">
+ <complexType>
+ <sequence>
+ <element name="responseType" type="string"/>
+ </sequence>
+ </complexType>
+ </element>
+ <element name="greetMe">
+ <complexType>
+ <sequence>
+ <element name="requestType" type="tns:MyStringType"/>
+ </sequence>
+ </complexType>
+ </element>
+ <element name="greetMeResponse">
+ <complexType>
+ <sequence>
+ <element name="responseType" type="string"/>
+ </sequence>
+ </complexType>
+ </element>
+ <element name="pingMe">
+ <complexType/>
+ </element>
+ <element name="pingMeResponse">
+ <complexType/>
+ </element>
+ <element name="faultDetail">
+ <complexType>
+ <sequence>
+ <element name="minor" type="short"/>
+ <element name="major" type="short"/>
+ </sequence>
+ </complexType>
+ </element>
+ </schema>
+ </wsdl:types>
+ <wsdl:message name="sayHiRequest">
+ <wsdl:part element="x1:sayHi" name="in"/>
+ </wsdl:message>
+ <wsdl:message name="sayHiResponse">
+ <wsdl:part element="x1:sayHiResponse" name="out"/>
+ </wsdl:message>
+ <wsdl:message name="greetMeRequest">
+ <wsdl:part element="x1:greetMe" name="in"/>
+ </wsdl:message>
+ <wsdl:message name="greetMeResponse">
+ <wsdl:part element="x1:greetMeResponse" name="out"/>
+ </wsdl:message>
+ <wsdl:message name="pingMeRequest">
+ <wsdl:part name="in" element="x1:pingMe"/>
+ </wsdl:message>
+ <wsdl:message name="pingMeResponse">
+ <wsdl:part name="out" element="x1:pingMeResponse"/>
+ </wsdl:message>
+ <wsdl:message name="pingMeFault">
+ <wsdl:part name="faultDetail" element="x1:faultDetail"/>
+ </wsdl:message>
+ <wsdl:portType name="Greeter">
+ <wsdl:operation name="sayHi">
+ <wsdl:input message="tns:sayHiRequest" name="sayHiRequest"/>
+ <wsdl:output message="tns:sayHiResponse" name="sayHiResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="greetMe">
+ <wsdl:input message="tns:greetMeRequest" name="greetMeRequest"/>
+ <wsdl:output message="tns:greetMeResponse" name="greetMeResponse"/>
+ </wsdl:operation>
+ <wsdl:operation name="pingMe">
+ <wsdl:input name="pingMeRequest" message="tns:pingMeRequest"/>
+ <wsdl:output name="pingMeResponse" message="tns:pingMeResponse"/>
+ <wsdl:fault name="pingMeFault" message="tns:pingMeFault"/>
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="Greeter_SOAPBinding" type="tns:Greeter">
+ <soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
+ <wsdl:operation name="sayHi">
+ <soap:operation soapAction="" style="document"/>
+ <wsdl:input name="sayHiRequest">
+ <soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="sayHiResponse">
+ <soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="greetMe">
+ <soap:operation soapAction="" style="document"/>
+ <wsdl:input name="greetMeRequest">
+ <soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output name="greetMeResponse">
+ <soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="pingMe">
+ <soap:operation style="document"/>
+ <wsdl:input>
+ <soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal"/>
+ </wsdl:output>
+ <wsdl:fault name="pingMeFault">
+ <soap:fault name="pingMeFault" use="literal"/>
+ </wsdl:fault>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="SOAPService">
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Mortimer">
+ <soap:address location="http://localhost:9000/Mortimer"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Tarpin">
+ <soap:address location="https://localhost:9003/Tarpin"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Rethwel">
+ <soap:address location="http://localhost:9004/Rethwel"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Gordy">
+ <soap:address location="https://localhost:9001/Gordy"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Bethal">
+ <soap:address location="https://localhost:9002/Bethal"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Hurlon">
+ <soap:address location="http://localhost:9006/Hurlon"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Poltim">
+ <soap:address location="https://localhost:9005/Poltim"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Abost">
+ <soap:address location="https://localhost:9007/Abost"/>
+ </wsdl:port>
+ <wsdl:port binding="tns:Greeter_SOAPBinding" name="Morpit">
+ <soap:address location="https://localhost:9008/Morpit"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>