Soap envelope namespace prefix in Java web service
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).
griboedov
Updated on June 10, 2020Comments
-
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.