Goal
I’m implementing a web service for quite an old (but sadly unchangeable) interface. I have an issue where the client that is calling my service expects a certain namespace in the SOAP response and I’m having difficulty in changing it to match.
Considering a hello world example, I want this:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:helloResponse xmlns:ns2="http://test/">
<return>Hello Catchwa!</return>
</ns2:helloResponse>
</S:Body>
</S:Envelope>
to look like this:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<customns:helloResponse xmlns:customns="http://test/">
<return>Hello Catchwa!</return>
</customns:helloResponse>
</S:Body>
</S:Envelope>
I found something similar to what I’m trying to do here but I’m having trouble getting similar code to execute properly. (I’d like to stick with Metro and not have to change to cxf or axis)
Execution
My implementation of JAXBContextFactory that returns a JAXBRIContext looks like this:
import com.sun.xml.bind.api.JAXBRIContext;
import com.sun.xml.bind.api.TypeReference;
import com.sun.xml.ws.api.model.SEIModel;
import com.sun.xml.ws.developer.JAXBContextFactory;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
public class HelloJaxbContext implements JAXBContextFactory
{
@Override
public JAXBRIContext createJAXBContext(SEIModel seim, List<Class> classesToBind, List<TypeReference> typeReferences) throws JAXBException {
List<Class> classList = new ArrayList<Class>();
classList.addAll(classesToBind);
List<TypeReference> refList = new ArrayList<TypeReference>();
for (TypeReference tr : typeReferences) {
refList.add(new TypeReference(new QName(tr.tagName.getNamespaceURI(), tr.tagName.getLocalPart(), "customns"), tr.type, tr.annotations));
}
return JAXBRIContext.newInstance(classList.toArray(new Class[classList.size()]), refList, null, seim.getTargetNamespace(), false, null);
}
}
Some test code for the web service is simply:
import com.sun.xml.ws.developer.UsesJAXBContext;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;
@WebService(serviceName = "Hello")
@UsesJAXBContext(value = HelloJaxbContext.class)
public class Hello
{
@WebMethod(operationName = "hello")
public String hello(@WebParam(name = "name") String txt)
{
return "Hello " + txt + "!";
}
}
Issues
In Tomcat 7.0.32 and Glassfish 3.1.2 using jaxws-rt 2.2.7 (from Maven), the above code doesn’t affect my web service output (the namespace prefix is still “ns2”).
If you started from the WSDL of the old service and generated all the various JAXB annotated request and response wrapper classes using
wsimport, then in the generated package you should find apackage-info.javasuch asJAXB provides a mechanism for you to suggest prefix mappings on the
@XmlSchemaannotation, so you could try modifyingpackage-info.javato readand see if that makes any difference to the generated messages. This also has the advantage of being pure JAXB spec (i.e. not dependent on the RI-specific custom context factory).
If you need to re-run
wsimportyou can prevent it from overwriting your modifiedpackage-infoby passing the-npaoption toxjc(this tells it not to generate apackage-info.javabut instead to put all the necessarynamespacesettings on the class-level annotations instead). Exactly how you do this depends how you’re runningwsimport.command line:
Ant:
Maven: