Изменение префикса пространства имен XML по умолчанию, сгенерированного JAXWS
Я использую JAXWS для создания клиента WebService для Java-приложения, которое мы создаем.
Когда JAXWS создает свои XML файлы для использования в протоколе SOAP, он генерирует следующий префикс пространства имен:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body ...>
<!-- body goes here -->
</env:Body>
</env:Envelope>
Моя проблема в том, что мой Counterpart (крупная компания по переводу денег), которая управляет сервером, к которому подключается мой клиент, отказывается принять вызов WebService (, пожалуйста, не спрашивайте меня, почему), если только XMLNS (префикс XML-имени) soapenv
). Вот так:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body ...>
<!-- body goes here -->
</soapenv:Body>
</soapenv:Envelope>
Итак, мой вопрос:
Есть ли способ, которым я управляю JAXWS (или любой другой технологией клиента Java WS) для генерации клиентов с использованием soapenv
вместо env
в качестве префикса XMLNS
? Существует ли API-вызов для настройки этой информации?
Спасибо!
Ответы
Ответ 1
Возможно, это поздно для вас, и я не уверен, что это может сработать, но вы можете попробовать.
Сначала вам нужно реализовать SoapHandler, а в handleMessage
вы можете изменить SOAPMessage
. Я не уверен, что вы можете напрямую изменить этот префикс, но можете попробовать:
public class MySoapHandler implements SOAPHandler<SOAPMessageContext>
{
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext)
{
try
{
SOAPMessage message = soapMessageContext.getMessage();
// I haven't tested this
message.getSOAPHeader().setPrefix("soapenv");
soapMessageContext.setMessage(message);
}
catch (SOAPException e)
{
// Handle exception
}
return true;
}
...
}
Затем вам нужно создать HandlerResolver
:
public class MyHandlerResolver implements HandlerResolver
{
@Override
public List<Handler> getHandlerChain(PortInfo portInfo)
{
List<Handler> handlerChain = Lists.newArrayList();
Handler soapHandler = new MySoapHandler();
String bindingID = portInfo.getBindingID();
if (bindingID.equals("http://schemas.xmlsoap.org/wsdl/soap/http"))
{
handlerChain.add(soapHandler);
}
else if (bindingID.equals("http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/"))
{
handlerChain.add(soapHandler);
}
return handlerChain;
}
}
И, наконец, вам нужно добавить свой HandlerResolver
к вашему клиентскому сервису:
Service service = Service.create(wsdlLoc, serviceName);
service.setHandlerResolver(new MyHandlerResolver());
Ответ 2
Этот пост, хотя и слишком поздно для оригинального плаката, призван помочь другим, кто может столкнуться с этим. Мне пришлось решить эту проблему за последние несколько дней. В частности, мне нужно было изменить префиксы, используемые в конверте SOAP, потому что поставщик услуг требовал, чтобы префиксы пространства имен соответствовали очень конкретному шаблону. В соответствии с этим шаблоном требуется изменить префикс пространства имен для элементов оболочки, заголовка и тела и тела (из стандартных, введенных JAX-WS). Вот схема решения, которое я использовал:
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class MyMessageNamespaceMapper implements SOAPHandler<SOAPMessageContext> {
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
final Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// only process outbound messages
if (outbound) {
try {
final SOAPMessage soapMessage = context.getMessage();
final SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
final SOAPHeader soapHeader = soapMessage.getSOAPHeader();
final SOAPBody soapBody = soapMessage.getSOAPBody();
// STEP 1: add new prefix/namespace entries
soapEnvelope.addNamespaceDeclaration("S1", "http://schemas.xmlsoap.org/soap/envelope/");
soapEnvelope.addNamespaceDeclaration("FOO-1", "http://foo1.bar.com/ns");
// STEP 2: set desired namespace prefixes
// set desired namespace prefix for the envelope, header and body
soapEnvelope.setPrefix("S1");
soapHeader.setPrefix("S1");
soapBody.setPrefix("S1");
addDesiredBodyNamespaceEntries(soapBody.getChildElements());
// STEP 3: remove prefix/namespace entries entries added by JAX-WS
soapEnvelope.removeNamespaceDeclaration("S");
soapEnvelope.removeNamespaceDeclaration("SOAP-ENV");
removeUndesiredBodyNamespaceEntries(soapBody.getChildElements());
// IMPORTANT! "Save" the changes
soapMessage.saveChanges();
}
catch (SOAPException e) {
// handle the error
}
}
return true;
}
private void addDesiredBodyNamespaceEntries(Iterator childElements) {
while (childElements.hasNext()) {
final Object childElementNode = childElements.next();
if (childElementNode instanceof SOAPElement) {
SOAPElement soapElement = (SOAPElement) childElementNode;
// set desired namespace body element prefix
soapElement.setPrefix("FOO-1");
// recursively set desired namespace prefix entries in child elements
addDesiredBodyNamespaceEntries(soapElement.getChildElements());
}
}
}
private void removeUndesiredBodyNamespaceEntries(Iterator childElements) {
while (childElements.hasNext()) {
final Object childElementNode = childElements.next();
if (childElementNode instanceof SOAPElement) {
SOAPElement soapElement = (SOAPElement) childElementNode;
// we remove any prefix/namespace entries added by JAX-WS in the body element that is not the one we want
for (String prefix : getNamespacePrefixList(soapElement.getNamespacePrefixes())) {
if (prefix != null && ! "FOO-1".equals(prefix)) {
soapElement.removeNamespaceDeclaration(prefix);
}
}
// recursively remove prefix/namespace entries in child elements
removeUndesiredBodyNamespaceEntries(soapElement.getChildElements());
}
}
}
private Set<String> getNamespacePrefixList(Iterator namespacePrefixIter) {
Set<String> namespacePrefixesSet = new HashSet<>();
while (namespacePrefixIter.hasNext()) {
namespacePrefixesSet.add((String) namespacePrefixIter.next());
}
return namespacePrefixesSet;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
@Override
public void close(MessageContext context) {
}
}
Установка обработчика обработчика выше в экземпляре класса службы (сгенерированного JAX-WS/wsimport) выглядит следующим образом:
yourWebServiceClient.setHandlerResolver(new HandlerResolver() {
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
return Arrays.asList(new MyMessageNamespaceMapper());
}
});