I have a jax-ws client ganerated with CXF
The request have a string-parameter (MGRequest) that contains an xml, all work's but the generated request is like this:
<S:Body>
<ns5:MGRequest><mytag>hello</mytag></ns5:MGRequest>
</S:Body>
I need to generate the body like:
<S:Body>
<ns5:MGRequest><![CDATA[<mytag>hello</mytag>]]></ns5:MGRequest>
</S:Body>
(because i can't control the server..)
The client is like a standard jax-ws:
@WebService(name = "ServiceSoap")
@XmlSeeAlso({ ObjectFactory.class})
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface ServiceSoap {
@WebMethod(operationName = "ProcessMessage")
@WebResult(name = "MGResponse")
public String processMessage(
@WebParam(partName = "input", name = "MGRequest") String input);
}
And i call like this:
Service client = new Service(url);
client.setHandlerResolver(HandlerFactory.build(new LoggerHandler()));
ServiceSoap service = client.getServiceSoap();
String msgToSend = JaxbUtil.jaxbObjToString(xmlObj, false);
String response = service.processMessage(msgToSend);
I have tried adding @XmlJavaTypeAdapter(CDataAdapter.class)
before @WebParam
but the result was:
<S:Body>
<ns5:MGRequest><![CDATA[<mytag>hello</mytag>]]></ns5:MGRequest>
</S:Body>
Where CDataAdapter:
public class CDataAdapter extends XmlAdapter<String, String> {
@Override
public String marshal(String v) throws Exception {
return "<![CDATA[" + v + "]]>";
}
@Override
public String unmarshal(String v) throws Exception {
return v;
}
}
Any idea how to archive that? Thanks
After a working night i've found the solution:
adding a javax.xml.ws.handler.Handler
to the client like this:
client.setHandlerResolver(HandlerFactory.build(new LoggerHandler(), new CDataHandler()));
where my HandlerFactory build a Handler:
public static HandlerResolver build(final Handler... handlers) {
return new HandlerResolver() {
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<Handler>();
if (handlers != null) {
for (Handler handler : handlers) {
handlerChain.add(handler);
}
}
return handlerChain;
}
};
}
import javax.xml.namespace.QName;
import javax.xml.soap.Node;
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;
public class CDataHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public void close(MessageContext context) {
}
@Override
public boolean handleMessage(SOAPMessageContext soapMessage) {
try {
SOAPMessage message = soapMessage.getMessage();
boolean isOutboundMessage = (Boolean) soapMessage
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// is a request?
if (isOutboundMessage) {
// build a CDATA NODE with the text in the root tag
Node cddata = (Node) message.getSOAPPart().createCDATASection(
message.getSOAPBody().getFirstChild().getTextContent());
// add the CDATA's node at soap message
message.getSOAPBody().getFirstChild().appendChild(cddata);
// remove the text tag with the raw text that will be escaped
message.getSOAPBody().getFirstChild()
.removeChild(message.getSOAPBody().getFirstChild().getFirstChild());
}
} catch (Exception ex) {
// fail
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext soapMessage) {
return true;
}
@Override
public Set<QName> getHeaders() {
return Collections.EMPTY_SET;
}
}
This is a simple class, i had only one tag with text, but in more complex scenario you can take the necessary action navigating the DOM.