Несоответствие префикса и структуры пространства имен запроса SOAP с использованием Spring Boot и JAXB

Я работаю над проектом Spring Boot, где мне нужно использовать веб-службу SOAP. Я использовал wsdl2java для генерации клиентского кода. Однако у меня возникли проблемы со сгенерированной структурой сообщения запроса SOAP.

Вот ожидаемый запрос SOAP от SOAP-UI:

<soapenv:Envelope xmlns:soapenv = "http://schemas.xmlsoap.org/soap/envelope/" xmlns:uri = "http://uri.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <uri:GetPolicy>
         <uri:policyId>12345</uri:policyId>
      </uri:GetPolicy>
   </soapenv:Body>
</soapenv:Envelope>

Однако мое приложение Spring Boot генерирует следующий запрос SOAP:

<SOAP-ENV:Envelope xmlns:SOAP-ENV = "http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns3:GetPolicy xmlns:ns2 = "http://schemas.data.org/PolicyServicesLibrary" xmlns:ns3 = "http://uri.org/" xmlns:ns4 = "http://schemas.microsoft.com/Serialization/Arrays" xmlns:ns5 = "http://schemas.microsoft.com/Serialization/">
            <ns3:policyId>12345</ns3:policyId>
        </ns3:GetPolicy>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Различия заключаются в следующем: при попытке я получаю сообщение об ошибке из-за неправильной полезной нагрузки SOAP запроса.

  1. Префиксы пространства имен (soapenv или SOAP-ENV).
  2. Дополнительные ненужные пространства имен.

Вот мой GetPolicy класс:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "policyId"
})
@XmlRootElement(name = "GetPolicy")
public class GetPolicy {

    @XmlElementRef(name = "policyId", namespace = "http://uri.org/", type = JAXBElement.class, required = false)
    protected JAXBElement<String> policyId;

    public JAXBElement<String> getPolicyId() {
        return policyId;
    }

    public void setPolicyId(JAXBElement<String> value) {
        this.policyId = value;
    }
}

И вот конфигурация и код, в котором я выполняю запрос:

@Autowired
private WebServiceTemplate webServiceTemplate;

ObjectFactory factory = new ObjectFactory();
GetPolicy request = factory.createGetPolicy();
request.setPolicyId(factory.createGetPolicyPolicyId("12345"));

webServiceTemplate.setMarshaller(jaxb2Marshaller);
webServiceTemplate.setUnmarshaller(jaxb2Marshaller);
webServiceTemplate.setDefaultUri("SOAP_SERVER_URL");

JAXBElement<GetPolicyResponse> response = (JAXBElement<GetPolicyResponse>) webServiceTemplate.marshalSendAndReceive(request, new SoapActionCallback("SOAP_ACTION"));
return response.getValue();

Я также обеспечил правильное определение пространства имен на уровне пакета в package-info.java:

@jakarta.xml.bind.annotation.XmlSchema(
    namespace = "http://uri.org/",
    elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED
)
package my.package.name;

Несмотря на эти конфигурации, сгенерированный запрос SOAP имеет неправильные префиксы пространства имен и включает дополнительные пространства имен. Кроме того, я знаю, что, добавив XmlNs, я могу исправить проблему с префиксом, но у меня есть несколько namespaceURI, которые должны соответствовать одному и тому же prefix. Вот на этом я и застрял.

Вопросы:

  1. Как я могу гарантировать, что сгенерированный запрос SOAP использует soapenv в качестве префикса пространства имен вместо SOAP-ENV?
  2. Как я могу предотвратить включение ненужных пространств имен в сгенерирован SOAP-запрос?

Спасибо. Любая помощь будет принята с благодарностью!

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На ваш первый вопрос: чтобы изменить префиксы пространства имен (SOAP-ENV на Soapenv), вам необходимо реализовать ClientInterceptor и установить для него значение WebServiceTemplate.

import jakarta.xml.soap.*;
import lombok.SneakyThrows;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.saaj.SaajSoapMessage;

public class Interceptor implements ClientInterceptor {

    @SneakyThrows
    public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
        changePrefix(messageContext);
        return true;
    }

    public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
        // if you need to change in the response call the method 'changePrefix' here
        return true;
    }

    public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
        // if you need to change in the fault response call the method 'changePrefix' here
        return true;
    }

    public void afterCompletion(MessageContext messageContext, Exception e) throws WebServiceClientException {

    }

    private void changePrefix(MessageContext messageContext) throws SOAPException {
        SaajSoapMessage soapMessage = (SaajSoapMessage) messageContext.getRequest();

        SOAPEnvelope soapEnvelope = soapMessage.getSaajMessage().getSOAPPart().getEnvelope();
        SOAPHeader soapHeader = soapEnvelope.getHeader();
        SOAPBody soapBody = soapEnvelope.getBody();
        SOAPFault soapFault = soapBody.getFault();

        soapEnvelope.removeNamespaceDeclaration(soapEnvelope.getPrefix());
        soapEnvelope.addNamespaceDeclaration("soapenv", soapEnvelope.getNamespaceURI());
        soapEnvelope.setPrefix("soapenv");

        if (soapHeader != null) soapHeader.setPrefix("soapenv");
        if (soapBody != null) soapBody.setPrefix("soapenv");
        if (soapFault != null) soapFault.setPrefix("soapenv");
    }
}

Чтобы установить это значение в webServiceTemplate, вы можете создать Bean или любой другой метод, который вам нравится, добавить созданный перехватчик в массив new ClientInterceptor[],

webServiceTemplate.setInterceptors(new ClientInterceptor[]{interceptor});

На ваш второй вопрос: да, вы можете использовать package-info.java и добавить XmlNs, когда вам нужно изменить другие префиксы в теле мыла на namespaceURI.

Большое спасибо за ответ и уделенное время, чтобы ответить на этот вопрос.

Abraham Arnold 01.06.2024 17:11

Другие вопросы по теме