JAXBでCDATAセクションの出力

JAXBのUnmarshalerを使用してXML出力を行うと、CDATAセクションは使用されません。

https://jaxb.dev.java.net/faq/JaxbCDATASample.java

では、org.apache.xml.serialize.XMLSerializer を使った方法が紹介されていますが、XMLSerializer は deprecated なので、できれば他の方法が望ましいです。


ここでは javax.xml.stream.XMLEventWriter を使う方法を紹介します。
XMLEventWriterではXMLの出力を、「XMLのイベントを書き込む」という形で実現します。

JAXBのMarshalerからこのXMLEventWriterに出力をすることができるのですが、そのXMLのイベントを補足して書き換えることによって、CDATAセクションの出力を実現します。

以下はサンプルです。
すべての「文字列を出力する」XMLイベントを、「CDATAセクションを出力する」XMLイベントに書き換えています。

public class CDataEventWriterAdapter implements XMLEventWriter {

    /**
     * XMLEventWriter
     */
    private XMLEventWriter writer;

    /**
     * @param writer
     */
    public CDataEventWriterAdapter(XMLEventWriter writer) {
        this.writer = writer;
    }

    @Override
    public void add(XMLEvent event) throws XMLStreamException {
        if (event.isCharacters()) {
            event = XMLEventFactory.newInstance()
                    .createCData(event.asCharacters().getData());
        }
        writer.add(event);
    }

    ....
}

このアダプタークラスを、Unmarshalerの出力時に使用します。

JAXBContext context = JAXBContext.newInstance(XXX.class);
Marshaler marshaler = context.createMarshaler();

StringWriter writer = new StringWriter();
XMLEventWriter xmlEventWriter= XMLOutputFactory.newInstance().createXMLEventWriter(writer);
marshaller.marshal(model, new CDataEventWriter(xmlEventWriter));

すべての文字列がCDATAセクションで囲まれて出力されます。