Search code examples
javadocx4j

How to Handle Breaking Change in Interface of docx4j Class "FlatOpcXmlCreator" in V11.3.2 (aka V8.3.0)


I'm about to update our project's dependencies and found out docx4j has changed it's interface of class FlatOpcXmlCreator. The get() method is now not only deprecated but completely deactivated as the following docx4j code snippet shows:

package org.docx4j.convert.out.flatOpcXml;
public class FlatOpcXmlCreator implements Output {
...
@Deprecated
public Package get() throws Docx4JException {
    throw new Docx4JException("Deprecated.");
}

(IMHO I think here they just skipped the usual deprecated step of still supporting the functionality, giving a warning and documenting hints how to upgrade to the new interface). Anyway, now the following code does not work anymore (since the last line calls the deprecated get() method).

JAXBContext jc = Context.jcXmlPackage;
Marshaller marshaller = jc.createMarshaller();
org.w3c.dom.Document doc = XmlUtils.neww3cDomDocument();

FlatOpcXmlCreator worker = new FlatOpcXmlCreator(wordPackage);
marshaller.marshal(worker.get(), doc);

Does anybody know how to fix it? I checked the release news. The change ist mentioned here, but without more details: https://www.docx4java.org/forums/announces/docx4j-8-3-0-released-t2992.html

Just some details to the actual version switch I tried (because versioning here is not totally abvious):

  • The change happened in V8.3.0.
  • V11.3.2 is the Java 11's branch of V8.3.2.
  • We were using V11.2.9 before.
  • The error occurred when I switched to V11.3.2.

The release news of V8.3.0 mentioned the change in FlatOpcXmlCreator was due to the following issue: https://github.com/plutext/docx4j/issues/444. I had a short look at the discussion but couldn't find any helpful information regards my issue.


Edit: In my example worker.get() was used as a shortcut to get a dom representation of the document. Because that was a little bit hacky (it's not FlatOpcXmlCreator's scope to expose it's internal structure) the current version of docx4j just can't fulfill our needs. A solution would be to apply Jason's solution and parse the string ourself.


Solution: Following JasonPlutext's suggestions (especially the one from the comment section) led to the following fix:

FlatOpcXmlCreator worker = new FlatOpcXmlCreator(wordPackage);
worker.populate();

var outputStream = new ByteArrayOutputStream();
worker.marshal(outputStream);
org.w3c.dom.Document doc = XmlUtils.getNewDocumentBuilder().parse(
    new ByteArrayInputStream(outputStream.toByteArray()));

Solution

  • For an example of what to do now, please see https://github.com/plutext/docx4j/blob/master/docx4j-core/src/main/java/org/docx4j/openpackaging/packages/OpcPackage.java#L735

            FlatOpcXmlCreator opcXmlCreator = new FlatOpcXmlCreator(this);
            opcXmlCreator.populate();
            opcXmlCreator.marshal(outStream);
    

    Given your wordPackage, just wordPackage.save(outStream, Docx4J.FLAG_SAVE_FLAT_XML)