SOAP response not unmarshalling to Java object

  Kiến thức lập trình

We have an XML SOAP response which is not getting unmarshalled to the any of the fields spec’d in xsd using Spring WS.

Here is the calling code:

import lombok.RequiredArgsConstructor;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.client.core.SoapActionCallback;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class EventClient {

    private final String soapAction;
    private final WebServiceTemplate webServiceTemplate;

    public boolean event(String uri, TestEvent request) {
        boolean successful = false;

        try {
            Object responseObj = webServiceTemplate.marshalSendAndReceive(uri, request, new SoapActionCallback(soapAction));
            if (responseObj instanceof EventResponse myResponse) {
               //breakpoint here shows all fields in myResponse are empty
               
               return true;
            }
        } catch (WebServiceException webServiceException) {
            // bla
        }
       return false;
    }
}

Here is the bean configuration:

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
@EnableConfigurationProperties(EventConfigurationProperties.class)
public class EventConfiguration {

    public HttpComponentsMessageSender httpComponentsMessageSender() {
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setAcceptGzipEncoding(false);
        return httpComponentsMessageSender;
    }

    @Bean
    public Jaxb2Marshaller marshaller() {
        var marshaller = new Jaxb2Marshaller();
        marshaller.setPackagesToScan("com.myurl");
        return marshaller;
    }

    @Bean
    @Primary
    public WebServiceTemplate eventWebServiceTemplate(Jaxb2Marshaller marshaller) {
        var webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(marshaller);
        webServiceTemplate.setUnmarshaller(marshaller);
        webServiceTemplate.setMessageSender(httpComponentsMessageSender());
        return webServiceTemplate;
    }

    @Bean
    public String soapAction(EventConfigurationProperties eventConfigurationProperties) {
        return eventConfigurationProperties.getSoapAction().toExternalForm();
    }
}

Configuration properties:

import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import java.net.URL;

@ConfigurationProperties("events.my-event")
@Validated
@Getter
@Setter
@ToString
public class EventConfigurationProperties {

    @NotNull
    private URL soapAction;

}

Config within application.yaml:

  events:
    schema: "src/main/resources/schemas/my-event.xsd"
    my-event:
      soap-action: http://www.MyUrl.com/MyEvent

XSD:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://www.MyUrl.com"
  targetNamespace="http://www.MyUrl.com">

  <xs:element name="MyEvent">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="testField" type="xs:string" minOccurs="1" maxOccurs="1"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:element name="MyEventResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="MyEventResult" type="xs:int"/>
        <xs:element name="TestString" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

When an integration test is run mocking the response that should come back from the webServiceTemplate.marshalSendAndReceive() call, the mocked data does not get mapped into the generated Java object MyEventResponse object.

Here is the XML that we are trying to use to test this:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><MyEventResponse xmlns="http://www.MyUrl.com"><MyEventResult>1</MyEventResult><TestString>"123"</TestString></MyEventResponse></soap:Body></soap:Envelope>""";

What are we missing?

LEAVE A COMMENT