Changing the default XML namespace prefix generated with JAXWS
I am usin开发者_开发技巧g 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 following namespace prefix:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body ...>
<!-- body goes here -->
</env:Body>
</env:Envelope>
My problem is that my Counterpart (a big money transfer company) which manages the server my client is connecting to, refuses to accept the WebService call (please don't ask my why) unless the XMLNS (XML namepspace prefix is soapenv
). Like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body ...>
<!-- body goes here -->
</soapenv:Body>
</soapenv:Envelope>
So my question is:
Is there a way I command JAXWS (or any other Java WS client technology) to generate clients using soapenv
instead of env
as the XMLNS
prefix? Is there an API call to set this information?
Thanks!
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());
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());
}
});
精彩评论