wsdljax-wssoap-client

Jakarta WS: generated envelope xml wrong


After solving a lot of issues to consume a soap webservice, I almost succeeded to make it work.

The generated envelope xml comes with an unwanted tag <arg0>, which makes it unreadable for the SOAP Webservice Provider:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header>
    <wsse:Security
      xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
      xmlns:S="http://crediconnect.ch/V2/02/" S:mustUnderstand="true"
      xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>username</wsse:Username>
        <wsse:Password
          Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
          ********
        </wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </SOAP-ENV:Header>
  <S:Body>
    <ns2:GetHitList xmlns:ns2="http://crediconnect.ch/V2/02/"
      xmlns:ns3="http://schemas.creditreform.ch/2017/05"
    >
      <arg0>
        <ns2:searchedAddress>
          <ns3:What>Company</ns3:What>
          <ns3:Where>Place</ns3:Where>
          <ns3:Country>CH</ns3:Country>
        </ns2:searchedAddress>
        <ns2:searchFilter>
          <ns3:ArchiveType>Business MainArchive SubArchive Active</ns3:ArchiveType>
          <ns3:MatchLevel>High</ns3:MatchLevel>
        </ns2:searchFilter>
      </arg0>
    </ns2:GetHitList>
  </S:Body>
</S:Envelope>

I'm using following Jakarta WS version:

<dependency>
  <groupId>jakarta.xml.ws</groupId>
  <artifactId>jakarta.xml.ws-api</artifactId>
  <version>4.0.0</version>
</dependency>

<dependency>
  <groupId>com.sun.xml.ws</groupId>
  <artifactId>jaxws-rt</artifactId>
  <version>4.0.0</version>
</dependency>

This is the shortened wsdl:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:http="http://www.w3.org/ns/wsdl/http"
  xmlns:tns="http://crediconnect.ch/V2/03/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  name="CrediConnect2_3"
  targetNamespace="http://crediconnect.ch/V2/03/">
  <wsdl:documentation>CrediCONNECT V2.3.0.1</wsdl:documentation>
  <!-- V2.3.0.1: Added missing field to CollectionInfo <xs:element name="LastPaymentDate" type="xs:dateTime" nillable="true"/>-->
  <wsdl:types>
  <xs:schema elementFormDefault="qualified" targetNamespace="http://crediconnect.ch/V2/02/"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://crediconnect.ch/V2/02/">
    <xs:import namespace="http://schemas.creditreform.ch/2017/05"/>
    <xs:element name="GetHitList">
      <xs:complexType>
        <xs:sequence>
          <xs:element minOccurs="0" name="searchedAddress" nillable="true" type="q1:WhatWhereSearch"
            xmlns:q1="http://schemas.creditreform.ch/2017/05"/>
          <xs:element minOccurs="0" name="searchFilter" nillable="true" type="q2:SearchFilter"
            xmlns:q2="http://schemas.creditreform.ch/2017/05"/>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.creditreform.ch/2017/05"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.creditreform.ch/2017/05">
    <xs:import namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
    <xs:complexType name="WhatWhereSearch">
      <xs:sequence>
        <xs:element name="What" nillable="true" type="xs:string">
          <xs:annotation>
            <xs:appinfo>
              <DefaultValue EmitDefaultValue="false"
                xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>
            </xs:appinfo>
          </xs:annotation>
        </xs:element>
        <xs:element name="Where" nillable="true" type="xs:string">
          <xs:annotation>
            <xs:appinfo>
              <DefaultValue EmitDefaultValue="false"
                xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>
            </xs:appinfo>
          </xs:annotation>
        </xs:element>
        <xs:element name="Country" nillable="true" type="xs:string">
          <xs:annotation>
            <xs:appinfo>
              <DefaultValue EmitDefaultValue="false"
                xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>
            </xs:appinfo>
          </xs:annotation>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
    <xs:element name="WhatWhereSearch" nillable="true" type="tns:WhatWhereSearch"/>
    <xs:complexType name="SearchFilter">
      <xs:sequence>
        <xs:element minOccurs="0" name="ArchiveType" type="tns:ArchiveType">
          <xs:annotation>
            <xs:appinfo>
              <DefaultValue EmitDefaultValue="false"
                xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>
            </xs:appinfo>
          </xs:annotation>
        </xs:element>
        <xs:element minOccurs="0" name="MatchLevel" type="tns:MatchLevel">
          <xs:annotation>
            <xs:appinfo>
              <DefaultValue EmitDefaultValue="false"
                xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>
            </xs:appinfo>
          </xs:annotation>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
    <xs:element name="SearchFilter" nillable="true" type="tns:SearchFilter"/>
  </xs:schema>

  <wsdl:binding name="cc2UserNameBasicEndpoint" type="tns:CrediConnectWebservice">
  <wsdl:operation name="GetHitList">
    <http:operation location="https://soadev:8443/cam-crediconnect_v2" method="POST"/>
    <soap:operation soapAction="http://crediconnect.ch/V2/02/CrediConnectWebservice/GetHitList"
      style="document"/>
    <wsdl:input>
      <soap:header use="literal" part="authentication-header"
        message="tns:CrediConnectWebservice_GetHitList_InputMessage"/>
      <soap:body use="literal"/>
    </wsdl:input>
    <wsdl:output>
      <soap:body use="literal"/>
    </wsdl:output>
  </wsdl:operation>
  <wsdl:service name="CrediConnect2_3">
    <wsdl:port name="cc2UserNameBasicEndpoint" binding="tns:cc2UserNameBasicEndpoint">
      <soap:address location="https://soadev:8443/cam-crediconnect_v2"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

My SOAP Client Call:


    import jakarta.xml.bind.JAXBElement;
    import jakarta.xml.soap.SOAPException;
    import jakarta.xml.ws.BindingProvider;
    import jakarta.xml.ws.Service;
    import jakarta.xml.ws.WebServiceException;
    import jakarta.xml.ws.handler.Handler;
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.List;
    import javax.xml.namespace.QName;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    
    @Component
    public class CrediConnectClient {
    
      private static final Logger log = LoggerFactory.getLogger(CrediConnectClient.class);
    
      public List<HitListItem> getHitListExample() throws IOException, SOAPException {
    
        GetHitList request = new GetHitList();
    
        WhatWhereSearch whatWhereSearch = new WhatWhereSearch();
    
        SearchFilter searchFilter = new SearchFilter();
    
        whatWhereSearch.setWhat("Company");
        whatWhereSearch.setWhere("Place");
        whatWhereSearch.setCountry("CH");
        searchFilter.setMatchLevel(MatchLevel.HIGH);
        searchFilter.getArchiveType().add("Business MainArchive SubArchive Active");
    
        JAXBElement<WhatWhereSearch> whatWhereSearchJAXBElement = new JAXBElement<>(
            new QName("http://crediconnect.ch/V2/02/", "searchedAddress"), WhatWhereSearch.class,
            whatWhereSearch);
        JAXBElement<SearchFilter> searchFilterJAXBElement = new JAXBElement<>(
            new QName("http://crediconnect.ch/V2/02/", "searchFilter"), SearchFilter.class,
            searchFilter);
    
        request.setSearchedAddress(whatWhereSearchJAXBElement);
        request.setSearchFilter(searchFilterJAXBElement);
    
        URL wsdlURL = new File("src/main/resources/wsdl/CrediConnect.wsdl").toURI().toURL();
    
        // Specify the target namespace and service name
        QName serviceQName = new QName("http://crediconnect.ch/V2/02/", "CrediConnect2_3");
    
        // Create a Service instance
        Service service = Service.create(wsdlURL, serviceQName);
    
        // Extract the SOAP port from the service
        QName portQName = new QName("http://crediconnect.ch/V2/02/", "cc2UserNameBasicEndpoint");
        MySOAPPortType soapPort = service.getPort(portQName, MySOAPPortType.class);
    
        BindingProvider bindingProvider = (BindingProvider) soapPort;
        List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain();
    
        handlerChain.add(new PayloadLoggingHandler());
        bindingProvider.getBinding().setHandlerChain(handlerChain);
    
        GetHitListResponse response = new GetHitListResponse();
    
        // Invoke a SOAP operation with the populated request object
        try {
          response = soapPort.processRequest(request);
        } catch (WebServiceException e) {
          e.printStackTrace();
        }
    
        List<HitListItem> hitListItemList = response.getGetHitListResult().getValue().getHitListItem();
        return hitListItemList;
      }
    } 

And the WebService Interface:


    import jakarta.jws.WebMethod;
    import jakarta.jws.WebService;
    
    @WebService(targetNamespace = "http://crediconnect.ch/V2/02/")
    public interface MySOAPPortType {
    
      @WebMethod(operationName = "GetHitList")
      GetHitListResponse processRequest(GetHitList request);
    
    }

Can you help me, to find the reason, why <arg0> is generated in the envelope xml and how to avoid it?


Solution

  • Finally, I found the solution!

    With the annotation @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE), I was able to prevent Jakarta ws to wrap the content of my payload xml with <arg0>

    import jakarta.jws.WebMethod;
    import jakarta.jws.WebParam;
    import jakarta.jws.WebService;
    import jakarta.jws.soap.SOAPBinding;
    
    @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
    @WebService(targetNamespace = "http://crediconnect.ch/V2/02/")
    public interface MySOAPPortType {
    
        @WebMethod(operationName = "GetHitList")
        GetHitListResponse processRequest(GetHitList request);
    
    }
    
    

    I must say, it helped a lot to find out the issue by logging the payload with jakarta.xml.ws.handler.soap.SOAPHandler;

    Also the older documentation (not yet jakarta) helped as well: https://eclipse-ee4j.github.io/metro-jax-ws/2.3.3/docs/ch03.html