This is an automated email from the ASF dual-hosted git repository. dkulp pushed a commit to branch 3.4.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 1408a80fdc4dfa4fed0e23e22b2ae9e0e71a9e16 Author: Andriy Redko <drr...@gmail.com> AuthorDate: Wed Nov 23 19:41:46 2022 -0500 CXF-8796: IllegalArgumentException: argument type mismatch with code first RPC when parameter omitted (cherry picked from commit ac2f96db79ae7fb931295d721753cfd9df007d88) (cherry picked from commit f95cfdfdf4fd6ecee8132c8dc7f8d8a0f4e1badb) (cherry picked from commit 23662383f32d75defca89ece23d13afafd268b8d) --- .../apache/cxf/message/MessageContentsList.java | 47 +++---- .../org/apache/cxf/jaxws/body/RPCGreeterImpl.java | 36 ++++++ .../apache/cxf/jaxws/body/RpcBodyServerTest.java | 137 +++++++++++++++++++++ .../soapbody_rpc_provider/sayHello1Msg.xml | 33 +++++ .../soapbody_rpc_provider/sayHelloMsg.xml | 33 +++++ .../src/main/resources/wsdl/soapbody_rpc.wsdl | 80 ++++++++++++ 6 files changed, 335 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/org/apache/cxf/message/MessageContentsList.java b/core/src/main/java/org/apache/cxf/message/MessageContentsList.java index 31ff1bfe36..4b5cfa46fa 100644 --- a/core/src/main/java/org/apache/cxf/message/MessageContentsList.java +++ b/core/src/main/java/org/apache/cxf/message/MessageContentsList.java @@ -21,7 +21,9 @@ package org.apache.cxf.message; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.service.model.MessagePartInfo; @@ -38,6 +40,7 @@ public class MessageContentsList extends ArrayList<Object> { */ public static final Object REMOVED_MARKER = new Object(); private static final long serialVersionUID = -5780720048950696258L; + private final Set<Integer> removed = new HashSet<>(); public MessageContentsList() { super(6); @@ -65,25 +68,32 @@ public class MessageContentsList extends ArrayList<Object> { @Override public Object set(int idx, Object value) { ensureSize(idx); - return super.set(idx, value); + + if (value != REMOVED_MARKER) { + removed.remove(idx); + return super.set(idx, value); + } else { + removed.add(idx); + return super.set(idx, null); + } } private void ensureSize(int idx) { while (idx >= size()) { - add(REMOVED_MARKER); + removed.add(size()); + add(null); } } public Object put(MessagePartInfo key, Object value) { - ensureSize(key.getIndex()); - return super.set(key.getIndex(), value); + return set(key.getIndex(), value); } public boolean hasValue(MessagePartInfo key) { if (key.getIndex() >= size()) { return false; } - return super.get(key.getIndex()) != REMOVED_MARKER; + return !removed.contains(key.getIndex()); } /** @@ -92,8 +102,7 @@ public class MessageContentsList extends ArrayList<Object> { * is mapped, or {@code null} if mapped element is marked as removed. */ public Object get(MessagePartInfo key) { - Object o = super.get(key.getIndex()); - return o == REMOVED_MARKER ? null : o; + return super.get(key.getIndex()); } /** @@ -104,28 +113,4 @@ public class MessageContentsList extends ArrayList<Object> { public void remove(MessagePartInfo key) { put(key, REMOVED_MARKER); } - - /** - * Allocates a new array containing the elements of the underlying list. - * - * @return an array containing all the elements of this list which are not - * marked as removed and {@code null} instead of those elements which are - * marked as removed, producing the same sequence of the elements as when - * sequentially iterating through underlying list using {@code get(int)}. - * - * @see {@link #get(MessagePartInfo)} - */ - @Override - public Object[] toArray() { - final int size = size(); - Object[] array = new Object[size]; - for (int idx = 0; idx < size; ++idx) { - Object o = super.get(idx); - if (o != REMOVED_MARKER) { - array[idx] = o; - } - } - return array; - } - } diff --git a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/body/RPCGreeterImpl.java b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/body/RPCGreeterImpl.java new file mode 100644 index 0000000000..9122f834de --- /dev/null +++ b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/body/RPCGreeterImpl.java @@ -0,0 +1,36 @@ +/** + * 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. + */ + +package org.apache.cxf.jaxws.body; + +import org.apache.body_test.rpc.RPCGreeter; + +public class RPCGreeterImpl implements RPCGreeter { + + @Override + public String sayHello(String in1, String in2, java.lang.String[] in3) { + return "Yes!"; + } + + @Override + public String sayHello1(String in1, int in2, String[] in3) { + return "Yes!"; + } + +} diff --git a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/body/RpcBodyServerTest.java b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/body/RpcBodyServerTest.java new file mode 100644 index 0000000000..c20b465e83 --- /dev/null +++ b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/body/RpcBodyServerTest.java @@ -0,0 +1,137 @@ +/** + * 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. + */ + + +package org.apache.cxf.jaxws.body; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.URL; + +import javax.xml.namespace.QName; + +import jakarta.xml.soap.MessageFactory; +import jakarta.xml.soap.SOAPMessage; +import jakarta.xml.ws.Dispatch; +import jakarta.xml.ws.Endpoint; +import jakarta.xml.ws.Service; +import jakarta.xml.ws.soap.SOAPFaultException; +import org.apache.cxf.BusFactory; +import org.apache.cxf.jaxws.AbstractJaxWsTest; +import org.apache.header_test.rpc.SOAPRPCHeaderService; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class RpcBodyServerTest extends AbstractJaxWsTest { + + @Before + public void setUp() throws Exception { + BusFactory.setDefaultBus(getBus()); + + String address = "http://localhost:9105/SoapBodyRPCContext/SoapBodyRPCPort"; + Endpoint.publish(address, new RPCGreeterImpl()); + } + + @Test + public void testRPCInBodyObject() throws Exception { + URL wsdl = getClass().getResource("/wsdl/soapbody_rpc.wsdl"); + assertNotNull(wsdl); + + SOAPRPCHeaderService service = new SOAPRPCHeaderService( + wsdl, + new QName( + "http://apache.org/body_test/rpc", + "SOAPRPCBodyService")); + assertNotNull(service); + Dispatch<SOAPMessage> dispatch = service + .createDispatch(new QName("http://apache.org/body_test/rpc", "SoapRPCBodyPort"), + jakarta.xml.soap.SOAPMessage.class, Service.Mode.MESSAGE); + + MessageFactory factory = MessageFactory.newInstance(); + InputStream is = getClass().getClassLoader() + .getResourceAsStream("./soapbody_rpc_provider/sayHelloMsg.xml"); + SOAPMessage inMessage = factory.createMessage(null, is); + SOAPMessage response = dispatch.invoke(inMessage); + is.close(); + + try (ByteArrayOutputStream bout = new ByteArrayOutputStream()) { + response.writeTo(bout); + assertTrue(new String(bout.toByteArray()).contains("Yes!")); + } + } + + /** + * When arguments are of primitive type, the invocation fails (since 'null' + * placeholders could not be converted to primitive ones). + */ + @Test(expected = SOAPFaultException.class) + public void testRPCInBodyPrimitive() throws Exception { + URL wsdl = getClass().getResource("/wsdl/soapbody_rpc.wsdl"); + assertNotNull(wsdl); + + SOAPRPCHeaderService service = new SOAPRPCHeaderService( + wsdl, + new QName( + "http://apache.org/body_test/rpc", + "SOAPRPCBodyService")); + assertNotNull(service); + Dispatch<SOAPMessage> dispatch = service + .createDispatch(new QName("http://apache.org/body_test/rpc", "SoapRPCBodyPort"), + jakarta.xml.soap.SOAPMessage.class, Service.Mode.MESSAGE); + + MessageFactory factory = MessageFactory.newInstance(); + InputStream is = getClass().getClassLoader() + .getResourceAsStream("./soapbody_rpc_provider/sayHello1Msg.xml"); + SOAPMessage inMessage = factory.createMessage(null, is); + dispatch.invoke(inMessage); + is.close(); + } + + @Test + public void testRPCInBodyNoArguments() throws Exception { + URL wsdl = getClass().getResource("/wsdl/soapbody_rpc.wsdl"); + assertNotNull(wsdl); + + SOAPRPCHeaderService service = new SOAPRPCHeaderService( + wsdl, + new QName( + "http://apache.org/body_test/rpc", + "SOAPRPCBodyService")); + assertNotNull(service); + Dispatch<SOAPMessage> dispatch = service + .createDispatch(new QName("http://apache.org/body_test/rpc", "SoapRPCBodyPort"), + jakarta.xml.soap.SOAPMessage.class, Service.Mode.MESSAGE); + + MessageFactory factory = MessageFactory.newInstance(); + InputStream is = getClass().getClassLoader() + .getResourceAsStream("./soapbody_rpc_provider/sayHello2Msg.xml"); + SOAPMessage inMessage = factory.createMessage(null, is); + SOAPMessage response = dispatch.invoke(inMessage); + is.close(); + + try (ByteArrayOutputStream bout = new ByteArrayOutputStream()) { + response.writeTo(bout); + assertTrue(new String(bout.toByteArray()).contains("Yes!")); + } + } +} diff --git a/rt/frontend/jaxws/src/test/resources/soapbody_rpc_provider/sayHello1Msg.xml b/rt/frontend/jaxws/src/test/resources/soapbody_rpc_provider/sayHello1Msg.xml new file mode 100644 index 0000000000..3ae6ccc5d9 --- /dev/null +++ b/rt/frontend/jaxws/src/test/resources/soapbody_rpc_provider/sayHello1Msg.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://apache.org/body_test/rpc" + xmlns:SOAP-ENC = "http://schemas.xmlsoap.org/soap/encoding/" + xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"> + <soapenv:Header/> + <soapenv:Body> + <ns1:sayHello1> + <ns1:in1>1</ns1:in1> + <ns1:in3> + 222 + 333 + </ns1:in3> + </ns1:sayHello1> + </soapenv:Body> +</soapenv:Envelope> diff --git a/rt/frontend/jaxws/src/test/resources/soapbody_rpc_provider/sayHelloMsg.xml b/rt/frontend/jaxws/src/test/resources/soapbody_rpc_provider/sayHelloMsg.xml new file mode 100644 index 0000000000..c4280a4f02 --- /dev/null +++ b/rt/frontend/jaxws/src/test/resources/soapbody_rpc_provider/sayHelloMsg.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://apache.org/body_test/rpc" + xmlns:SOAP-ENC = "http://schemas.xmlsoap.org/soap/encoding/" + xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"> + <soapenv:Header/> + <soapenv:Body> + <ns1:sayHello> + <ns1:in1>1</ns1:in1> + <ns1:in3> + 222 + 333 + </ns1:in3> + </ns1:sayHello> + </soapenv:Body> +</soapenv:Envelope> diff --git a/testutils/src/main/resources/wsdl/soapbody_rpc.wsdl b/testutils/src/main/resources/wsdl/soapbody_rpc.wsdl new file mode 100644 index 0000000000..a611cfe1fd --- /dev/null +++ b/testutils/src/main/resources/wsdl/soapbody_rpc.wsdl @@ -0,0 +1,80 @@ +<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xformat="http://cxf.apache.org/bindings/xformat" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:x1="http://apache.org/body_test/rpc/types" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://apache.org/body_test/rpc" targetNamespace="http://apache.org/bo [...] + <wsdl:types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:x1="http://apache.org/body_test/rpc/types" targetNamespace="http://apache.org/body_test/rpc/types" elementFormDefault="qualified"> + <simpleType name="array"> + <list itemType="string"/> + </simpleType> + </schema> + </wsdl:types> + <wsdl:message name="sayHelloRequest"> + <wsdl:part name="in1" type="xsd:string"/> + <wsdl:part name="in2" type="xsd:string"/> + <wsdl:part name="in3" type="x1:array"/> + </wsdl:message> + <wsdl:message name="sayHelloResponse"> + <wsdl:part name="out" type="xsd:string"/> + </wsdl:message> + <wsdl:message name="sayHelloRequest1"> + <wsdl:part name="in1" type="xsd:string"/> + <wsdl:part name="in2" type="xsd:int"/> + <wsdl:part name="in3" type="x1:array"/> + </wsdl:message> + <wsdl:message name="sayHelloResponse1"> + <wsdl:part name="out" type="xsd:string"/> + </wsdl:message> + <wsdl:portType name="RPCGreeter"> + <wsdl:operation name="sayHello"> + <wsdl:input name="sayHelloRequest" message="tns:sayHelloRequest"/> + <wsdl:output name="sayHelloResponse" message="tns:sayHelloResponse"/> + </wsdl:operation> + <wsdl:operation name="sayHello1"> + <wsdl:input name="sayHelloRequest1" message="tns:sayHelloRequest1"/> + <wsdl:output name="sayHelloResponse1" message="tns:sayHelloResponse1"/> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="Greeter_SOAPBinding" type="tns:RPCGreeter"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + <wsdl:operation name="sayHello"> + <soap:operation style="rpc" soapAction="sayHello"/> + <wsdl:input> + <soap:body use="literal"/> + </wsdl:input> + <wsdl:output> + <soap:body use="literal"/> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="sayHello1"> + <soap:operation style="rpc" soapAction="sayHello"/> + <wsdl:input> + <soap:body use="literal"/> + </wsdl:input> + <wsdl:output> + <soap:body use="literal"/> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="SOAPRPCBodyService"> + <wsdl:port name="SoapRPCBodyPort" binding="tns:Greeter_SOAPBinding"> + <soap:address location="http://localhost:9105/SoapBodyRPCContext/SoapBodyRPCPort"/> + </wsdl:port> + </wsdl:service> +</wsdl:definitions>