Generate documents from a Word template with Docx4j on Wildfly

Last Updated:  July 6, 2020 | Published: September 9, 2018

Lately, I had the requirement to generate Word documents from a template and fill them dynamically with data. For this task, I compared the following Java libraries: Apache POI, iText PDF, Docx4j, and XDocreports.  I compared them while using the following characteristics: Possibility to replace variables, amount of additional dependencies, lines of code to generate the document, and the number of releases in the last year. The winning library was Docx4j.  In this blog post, I'll show you a simple way to generate Word documents from a Word template with Docx4j using Java EE and running on Wildfly. The application will accept data through a JAX-RS endpoint, populate the document and send the generated document back as a result.

Project setup for using Docx4j on WildFly

The pom.xml of the project looks like the following:

I am using the Docx4j library in version 6.1.2 and as this library is making use of JAXB and uses the JAXB namespace prefix mapping, I am adding an additional library to be able to use the JAXB reference implementation of Wildfly.

The Docx4j and the JAXBNamespacePrefixMapper dependencies are packed into the .war which is okay for this sample project, but for a thinner .war approach you can also add them to the Wildfly libs and mark them as provided in the pom.xml .

To be able to use the JAXB implementation of Wildfly, we need the following jboss-deployment-structure.xml under /src/main/webapp/WEB-INF:

Prepare the application to convert a Word template with Docx4j

The following POJO will be used for replacing the variables in the Word document with some data:

The JAX-RS endpoint looks like this:

We validate the incoming UserInformation object using Bean Validation and pass it to the DocxGenerator for replacing the variables. This endpoint returns the media type APPLICATION_OCTET_STREAM as we are sending the raw bytes to the client. In addition, I am adding the Content-Disposition header to inform the client about the attached document.

The required code for loading the document and replacing the variables is also rather simple:

The template.docx file is loaded into a Docx4j internal object and prepared for the variable replacement. For replacing the variables I created a HashMapwhere the key is the name of the variable and the value the content. Docx4j supports three approaches for replacing variables within a .docx file:

  1. Marking variables with ${} in the document
  2. Using the Word field format MERGEFIELD
  3. Using XPath to replace the content

In this example, I am using the first approach, which is the simplest one. The template.docx looks like the following and is placed under /src/main/resources :

Generate the PDF file on WildFly

To download a generated document you can now use a REST client like Postman and store the response to the filesystem or use this cURL command:

For a simple deployment on your machine, I created the following Dockerfile:

With the JAVA_OPTS environment variable, I am adding some memory restrictions for the JVM and with the parameter -Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true I am optimizing the performance and reducing the amount of required heap space for JAXB processing. You can find a detailed explanation for this here.

You can find the whole source code on GitHub and a detailed explanation for starting this application in the README.md.

Have fun with generating documents from a Word template with Docx4j on Wildfly,

Phil.

  • This method doesn’t work properly. I mean replacing variables with:
    documentPart.variableReplace(variables);

    since one variable, for example, ${firstname} may be separated in multiple runs in the word document. So, ‘variableReplace’ method cannot find such variables which are separated in multiple runs.

    • Hi Navid,

      thanks for reaching out. I did a quick test and added a second page to the template.docx with the ${firstName} variable in addition to page one and it worked. You can also have a look at the implementation of the .variableReplace() method and see what’s happening under the hood.

      If you want, I can share the example with multiple variable replacements with you.

      Kind regards,
      Phil

      • Hi Rieckpil,
        thanks for responding. Try this scenario:
        in the “${firstName}” variable in the word file, change the format of one character, for example, bold the letter N in ${firstName} and check whether this time it is replaced with the value or not.

        • Hey Navid,

          I tried it with the character ‘N’ and the whole variable in bold and it worked for me. With docx4j you have three different possible ways of replacing variables:

          1. Marking variables with ${} in the document
          2. Using the Word field format MERGEFIELD
          3. Using XPath to replace the content

          Maybe you can try a different solution

  • Hey Rieckpil,
    I had referred your code in GitHub I want to iterate the list one by one what I want to change in my template.Please help me to solve this

  • Hello,

    While using this I encountered an error like:
    Caused by: java.lang.NoClassDefFoundError: org/docx4j/openpackaging/packages/WordprocessingMLPackage

    I added the dependencies in pom.xml.
    I cant figure out why its not working.

  • Hey Rieckpil,

    Great exmaple!~

    I wanna inject an object into my template file like ${gender.title}, so i use this function documentPart.addObject(gender);
    but i got an error like “Caused by: javax.xml.bind.JAXBException: class com.xxx.xxx.dto.Gender ni aucune de ses superclasses n’est connue dans ce contexte.”

  • Hello I have followed your tutorial and I am running into the problem that it results in a corrupted word file. Can you help with this issue?

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    Join Our Mailing List To Get 3x Free Cheat Sheets

    Free Java Cheat Sheets
    >