spring-bootweb-servicessoapjaxbjaxb2-maven-plugin

Spring boot - Server did not recognize the value of HTTP Header SOAPAction


I want to consume soap service using jaxb. The generated request from jaxb is

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
      <ns2:Add xmlns:ns2="http://tempuri.org/">
         <ns2:intA>10</ns2:intA><ns2:intB>20</ns2:intB>
      </ns2:Add>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

But the response is a soap exception as stated in the title.

Caused by: org.springframework.ws.soap.client.SoapFaultClientException: System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: .
   at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
   at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
   at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
   at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)

Below is my soap config code. Source example: https://howtodoinjava.com/spring-boot/spring-soap-client-webservicetemplate/

    public class ConsumeSoapApplication {
            public static String wsdlurl = "http://www.dneonline.com/calculator.asmx?wsdl";
            public static void main(String[] args) {
                try {
                    JAXBContext.newInstance(com.dxc.service.soap.service.calc.ObjectFactory.class.getPackage().getName(),
                            com.dxc.service.soap.service.calc.ObjectFactory.class.getClassLoader());
                } catch (JAXBException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                SpringApplication.run(ConsumeSoapApplication.class, args);
            }

            @Bean
            CommandLineRunner lookup(SoapConnector soapConnector) {
                return args -> {
                    Integer a = 10;
                    Integer b = 20;
                    if(args.length>0){
                        a = Integer.parseInt(args[0]);
                        b = Integer.parseInt(args[1]);
                    }

                    Add add = new Add();
                    add.setIntA(a);
                    add.setIntB(b);
                    AddResponse addRes = (AddResponse) soapConnector.callWebService(wsdlurl, add);
                    System.out.println("Got Response As below ========= : ");
                    System.out.println("Added result : "+addRes.getAddResult());
                };
            }
        }

@Configuration
public class SoapConfig {    
    @Bean
        public Jaxb2Marshaller marshaller() {
            try {
                JAXBContext jb = JAXBContext.newInstance(com.dxc.service.soap.service.calc.ObjectFactory.class.getPackage().getName(),
                        com.dxc.service.soap.service.calc.ObjectFactory.class.getClassLoader());
                //Jaxb2Marshaller marshaller = (Jaxb2Marshaller) jb.createMarshaller();
                Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
                marshaller.setPackagesToScan("com.dxc.service.soap.service.calc");
                //marshaller.setContextPath("com.dxc.service.soap.calc");
                return marshaller;
            } catch (JAXBException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }   
            return null;
        }

        @Bean
        public SoapConnector soapConnector(Jaxb2Marshaller marshaller) {
            SoapConnector client = new SoapConnector();
            client.setDefaultUri("http://www.dneonline.com/calculator.asmx");
            client.setMarshaller(marshaller);
            client.setUnmarshaller(marshaller);
            return client;
        }

Please help me. Thanks.


Solution

  • The issue you're facing is that the web service at http://www.dneonline.com/calculator.asmx expects a SOAPAction header. And since you're not providing one the service have no idea how to route the request.

    The tutorial you're following doesn't require the SOAPAction header to do the routing.

    If you take a look at how the Add operation is specified in the the WSDL, you'll find the expected value of the SOAPAction header there. Same for all the other operations the service provides.

    <wsdl:operation name="Add">                                                           
      <soap:operation soapAction="http://tempuri.org/Add" style="document" />             
      <wsdl:input>                                                                        
        <soap:body use="literal" />                                                       
      </wsdl:input>                                                                       
      <wsdl:output>                                                                       
        <soap:body use="literal" />                                                       
      </wsdl:output>                                                                      
    </wsdl:operation>
    

    Assuming that your SoapConnector class is identical to the one in the tutorial you can remove the String url as input to the callWebservice method since that is already set via the client.setDefaultUri("http://www.dneonline.com/calculator.asmx"); in the SoapConnector bean. Instead, add String soapAction as an input parameter, giving you the following

    public class SOAPConnector extends WebServiceGatewaySupport {
    
        public Object callWebService(Object request, String soapAction){
            return getWebServiceTemplate().marshalSendAndReceive(url, new SoapActionCallback(soapAction));
        }
    }
    

    Then, remove the wsdlurl as input to soapConnector.callWebService (it was wrong anyway) and add the soapHeader value for the operation you want to use instead, leaving you with this

    @Bean
    CommandLineRunner lookup(SoapConnector soapConnector) {
        return args -> {
            Integer a = 10;
            Integer b = 20;
            if(args.length>0){
                a = Integer.parseInt(args[0]);
                b = Integer.parseInt(args[1]);
            }
    
            Add add = new Add();
            add.setIntA(a);
            add.setIntB(b);
            AddResponse addRes = (AddResponse) soapConnector.callWebService(add, "http://tempuri.org/Add");
            System.out.println("Got Response As below ========= : ");
            System.out.println("Added result : "+addRes.getAddResult());
        };
    }
    

    Of course, if you want to use other operations besides Add you'll have to tweak this solution to make it generic.