Changing the default XML namespace prefix generated with JAXWS

前端 未结 2 560
悲&欢浪女
悲&欢浪女 2020-11-29 07:30

I am using JAXWS to generate a WebService client for a Java Application we\'re building.

When JAXWS build its XMLs to use in SOAP protocol, it generates the followin

相关标签:
2条回答
  • 2020-11-29 08:06

    This post, while likely too late for the original poster, is intended to help others who may run into this. I had to solve this problem in the last few days. In particular, I needed to change the prefixes used in the SOAP envelope because the service provider required that the namespace prefixes conform to a very specific pattern. Conforming to this pattern required changing the namespace prefix for the envelope, header and body, and body elements (from the standard ones put in by JAX-WS). Here is an outline of the solution I used:

    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) {
      }
    }
    

    Setting the handler resolver above on an instance of the service class (generated by JAX-WS/wsimport) looks like this:

    yourWebServiceClient.setHandlerResolver(new HandlerResolver() {
      @Override
      public List<Handler> getHandlerChain(PortInfo portInfo) {
        return Arrays.asList(new MyMessageNamespaceMapper());
      }
    });
    
    0 讨论(0)
  • 2020-11-29 08:27

    Maybe it's late for you and I'm not sure if this may work, but you can try.

    First you need to implement a SoapHandler and, in the handleMessage method you can modify the SOAPMessage. I'm not sure if you can modify directly that prefix but you can try:

    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;
      }
    
      ...
    }
    

    Then you need to create a 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;
      }
    }
    

    And finally you'll have to add your HandlerResolver to your client service:

    Service service = Service.create(wsdlLoc, serviceName);
    service.setHandlerResolver(new MyHandlerResolver());
    
    0 讨论(0)
提交回复
热议问题