Soap envelope namespace prefix in Java web service

20,781

I think Customising JAX-WS prefix of a SOAP response summarizes your options.

Option 1: I think you just need to put this above your package.

@javax.xml.bind.annotation.XmlSchema(namespace = "http://schemas.xmlsoap.org/soap/envelope/",
   xmlns = { 
      @javax.xml.bind.annotation.XmlNs(prefix = "soap", 
         namespaceURI="http://schemas.xmlsoap.org/soap/envelope/")
    }
)

Option 2: Alternatively (also mentioned in the link), you could use a SOAPHandler. You could add a configuration file to bind these handlers. But in fact, you can just add them at runtime. I think this needs some explanation: The trick is to get an instance of the BindingProvider. This is different if you are a consumer or provider of the webservice.

If you are server (i.e. providing a webservice):

webservice = Class.forName(serviceClassName).newInstance();
Endpoint e = Endpoint.create(webservice);
BindingProvider bp = (BindingProvider)e.getBinding();
e.publish("http://localhost:" + serverPort + servicePath);

If you are client (i.e. consuming a webservice):

Service service = new Service(url, qname);
Port port = service.getPort();
BindingProvider bp = ((BindingProvider) port);

When you have the bindingprovider, you can bind the handler as follows.

List<Handler> chain = bp.getHandlerChain();
if (chain == null) chain = new ArrayList<Handler>();
chain.add(myCustomHandler);
bp.setHandlerChain(chain);

Now, for the chained handler itself, you should implement SOAPHandler<SOAPMessageContext>. There you can manipulate your messages however you like. (see linked post above for an example).

Share:
20,781
griboedov
Author by

griboedov

Updated on June 10, 2020

Comments

  • griboedov
    griboedov about 4 years

    I am trying to change prefix for soap envelope in response of web-service from S="http://schemas.xmlsoap.org/soap/envelope/" to soap="http://schemas.xmlsoap.org/soap/envelope/":

    so here's how the response looks like now:

    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
       <S:Body>
          <n:soaprequestResponse xmlns:n="http://tempuri.org/soaprequest">
             <n:soaprequestResult/>
          </n:soaprequestResponse>
       </S:Body>
    </S:Envelope>
    

    and here's how it must look like:

    <soap:Envelope xmlns:soap:="http://schemas.xmlsoap.org/soap/envelope/">
       <soap:Body>
          <n:soaprequestResponse xmlns:n="http://tempuri.org/soaprequest">
             <n:soaprequestResult/>
          </n:soaprequestResponse>
       </soap:Body>
    </soap:Envelope>
    

    How can this be attained?

    EDIT:

    I added soap handler class and the problem starts when I'm trying to get envelope:

    package org.tempuri.soaprequest;
    
    import java.util.Set;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.xml.namespace.QName;
    import javax.xml.soap.SOAPBody;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    
    
    public class SoapHandler implements SOAPHandler<SOAPMessageContext> {
    
        @Override
        public Set<QName> getHeaders() {
           //do nothing
           return null;
        }
    
        @Override
        public boolean handleMessage(SOAPMessageContext context) {
            if ((boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) { //Check here that the message being intercepted is an outbound message from your service, otherwise ignore.
                try {
                    SOAPEnvelope msg = context.getMessage().getSOAPPart().getEnvelope(); //just trying to get envelope
                } catch (SOAPException ex) {
                    ex.printStackTrace();
                }
    
            return true; //indicates to the context to proceed with (normal)message processing
        }
    
        @Override
        public boolean handleFault(SOAPMessageContext context) {
              //do nothing
           return true;
        }
    
        @Override
        public void close(MessageContext context) {
              //do nothing
    
        }
    }
    

    SoapUI throws:

    <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
        <faultcode>S:Server</faultcode>
            <faultstring>JVMVRFY012 stack shapeinconsistent;class=com/sun/xml/messaging/saaj/soap/SOAPDocumentImpl, method=createDocumentFragment()Lorg/w3c/dom/DocumentFragment;, pc=5
        </faultstring>
    </S:Fault>
    

    Tomcat log has no errors.

    It doesn't occur without custom soap handler.

    Perhaps the reason is in the way I implemented web method. It creates a new thread with an object that processes request and then returns empty response, thus releasing client from waiting for request processing is over:

    @WebResult(name="soaprequestResult", targetNamespace="http://tempuri.org/soaprequest")
    public SoaprequestResponse.SoaprequestResult soaprequest(@WebParam(name="streams", targetNamespace="http://tempuri.org/soaprequest") SoaprequestStreams streams) {
        try {
            new Thread(new MyProcess(streams)).start();
            return new SoaprequestResponse().getSoaprequestResult();
        } catch(Exception e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            String stackTrace = sw.toString();
            return new SoaprequestResponse().getSoaprequestResult();
        }
    }
    

    and MyProcess is class where request processing really is and stmt.executeUpdate is executed.