CDATA element in WSDL client
Asked Answered
E

1

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.

Emanative answered 20/6, 2016 at 12:27 Comment(4)
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.Hortensehortensia
I need this because, when i set the "dataRequest" with a CDATA string, it gets fully escaped.Emanative
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?Hortensehortensia
You didn't set CharacterEscapeHandler for marshaller, that's why you get all CDATA escaped. Check rest of https://mcmap.net/q/447594/-jaxb-marshalling-unmarshalling-with-cdata And AFAIK wsimport doesn't support setting marshaller property for client. CXF client support it cxf.apache.org/docs/jaxb.htmlXanthene
E
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!

Emanative answered 29/6, 2016 at 16:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.