8

I'm doing a WSDL client and want to know how I can set an XML element to be CDATA.

I'm using the wsimport to generate the source code, and the CDATA element is part of the request XML. This is the XML class of the request:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "dataRequest" }) 
@XmlRootElement(name = "ProcessTransaction")
public class ProcessTransaction {

    protected String dataRequest;

    public String getDataRequest() {
        return dataRequest;
    }

    public void setDataRequest(String value) {
        this.dataRequest = value;
    }  
} 

I've already tried the @XmlAdapter, but it changes nothing on the output...

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class AdaptorCDATA extends XmlAdapter<String, String> {

    @Override
    public String marshal(String arg0) throws Exception {
        return "<![CDATA[" + arg0 + "]]>";
    }

    @Override
    public String unmarshal(String arg0) throws Exception {
        return arg0;
    }
}

In the XML class:

@XmlJavaTypeAdapter(value=AdaptorCDATA.class)
protected String dataRequest;

I tried to debug, but it never steps on the AdaptorCDATA function.

The wsimport version is 2.2.9 and the jaxb-api version is 2.1.

Community
  • 1
  • 1
fabriciols
  • 959
  • 1
  • 12
  • 25
  • Why do you need this? Because you want to write xml-data to the element? This should work out-of-the-box. We have a xml-data string, set this as value in the corresponding element and then JAXB's magic wraps a CDATA all around when marshalling. – Frank Jun 23 '16 at 08:18
  • I need this because, when i set the "dataRequest" with a CDATA string, it gets fully escaped. – fabriciols Jun 23 '16 at 12:07
  • OK, I just tried your AdaptorCDATA with an arbitrary String member of one of our classes and it steps well into the `marshall()`-method. Looking at your question I see that you have a snippet where you have the `@XmlJavaTypeAdapter`-Annotation but not in the `ProcessTransaction`-class where it should be. If you have it there but the breakpoint is still not hit, maybe you have to rebuild and refresh before firing up the client? – Frank Jun 23 '16 at 12:46
  • 1
    You didn't set `CharacterEscapeHandler` for marshaller, that's why you get all CDATA escaped. Check rest of http://stackoverflow.com/a/14197860/1516873 And AFAIK wsimport doesn't support setting marshaller property for client. CXF client support it http://cxf.apache.org/docs/jaxb.html – user1516873 Jun 24 '16 at 10:33

1 Answers1

1

So, as @user1516873 suggested, i moved the code to cxf, and with this, is working well. Now i'm using the "wsdl2java" to generate the code, and the jars from cxf on my project.

What is different in the code:

CdataInterceptor

import javax.xml.stream.XMLStreamWriter;

import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

public class CdataInterceptor extends AbstractPhaseInterceptor<Message> {

    public CdataInterceptor() {
        super(Phase.MARSHAL);
    }

    public void handleMessage(Message message) {
        message.put("disable.outputstream.optimization", Boolean.TRUE);
        XMLStreamWriter writer = (XMLStreamWriter) message.getContent(XMLStreamWriter.class);
        if (writer != null && !(writer instanceof CDataContentWriter)) {
            message.setContent(XMLStreamWriter.class, new CDataContentWriter(writer));
        }
    }

    public void handleFault(Message messageParam) {
        System.out.println(messageParam);
    }
}

CDataContentWriter

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.apache.cxf.staxutils.DelegatingXMLStreamWriter;

public class CDataContentWriter extends DelegatingXMLStreamWriter {

    public CDataContentWriter(XMLStreamWriter writer) {
        super(writer);
    }

    public void writeCharacters(String text) throws XMLStreamException {
        boolean useCData = text.contains("RequestGeneric");
        if (useCData) {
            super.writeCData(text);
        } else {
            super.writeCharacters(text);
        }
    }

    // optional 
    public void writeStartElement(String prefix, String local, String uri) throws XMLStreamException {
        super.writeStartElement(prefix, local, uri);
    }
}

Using the Writer and the Interceptor:

MyService wcf = new MyService(url, qName);
IMyService a = wcf.getBasicHttpBinding();

Client cxfClient = ClientProxy.getClient(a);
CdataInterceptor myInterceptor = new CdataInterceptor();
cxfClient.getInInterceptors().add(myInterceptor);
cxfClient.getOutInterceptors().add(myInterceptor);

And it works perfect!

Community
  • 1
  • 1
fabriciols
  • 959
  • 1
  • 12
  • 25