Skip to content

verronpro/docx-stamper

Repository files navigation

Office-Stamper

Introduction

Office-Stamper (formerly Docx-Stamper) is a Java template engine that allows for dynamic creation of docx documents at runtime. You design a template using your preferred Word processor; and Office-Stamper will generate documents based on that template.

Build Status Build Status Build Status

Project Update

The project name has changed from Docx-Stamper to Office-Stamper to better signify its functionality and scope.

Release Notes

Version 1.6.8

This release marks an important milestone in our plans to transition to version 2.0. It introduces new APIs and deprecates some legacy ones. We recommend all users to start using the new APIs to reduce disruption in the future.

Transition to Java 9 Modularization

We are transitioning to Java 9 Modularization for added efficiency and developer-friendliness. It aids in separating the project’s core details from the interfaces that developers work with.

Upcoming in Version 2.0

Our upcoming release, version 2.0, is set to be a significant update with major improvements over the preceding versions. Please note the following changes:

  1. Discontinuation of legacy APIs and complete adoption of new ones.

  2. Full embrace of Java 9 modularization.

  3. Other improvements and optimizations which will be detailed in the release notes.

We appreciate your input and suggestions. Please feel free to contribute or share your thoughts with us.

Usage

Here is a simple code snippet exemplifying how to use Office-Stamper:

class Example {
    public static void main(String[] args) {
        // your own POJO against which expressions found in the template will be resolved
        var context = new YourPojoContext(_, _ , _);

        // Path to your .docx template file
        var templatePath = Paths.get("your/docx/template/file.docx");
        // Path to write the resulting .docx document
        var outputPath = Paths.get("your/desired/output/path.docx");

        var stamper = new DocxStamper();

        try(
            var template = Files.newInputStream(templatePath);
            var output = Files.newOutputStream(outputPath)
        ) {
            stamper.stamp(template, context, output);
        }
    }
}

Template Expressions and Their Usage

The foundation of Office-Stamper lies in its ability to replace expressions within the text of a .docx template document. Conveniently, add expressions such as ${person.name} or ${person.name.equals("Homer") ? "Duff" : "Budweiser"} in the text of the .docx file you’re using as a template. Then, provide a context object to resolve the placeholder. Don’t worry about formatting, Office-Stamper will maintain the original text’s formatting in the template. You have full access to the extensive feature set of [Spring Expression Language (SpEL)](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html).

Each placeholder’s resolution corresponds to the following types:

Table 1. Type that can be resolved to an element in the .docx document

Type of placeholder value

Effect

java.lang.Object

The placeholder is replaced by the String representation of the object (String.valueOf()).

java.lang.String

The placeholder is replaced with the String value.

java.util.Date

The placeholder is replaced by a formatted Date string (by default "dd.MM.yyyy"). You can change the format string by registering your own DateResolver.

java.time.LocalDate

The placeholder is replaced by a formatted Date string (by default DateTimeFormatter.ISO_LOCAL_DATE). You can change the format string by registering your own.

java.time.LocalDateTime

The placeholder is replaced by a formatted Date string (by default DateTimeFormatter.ISO_LOCAL_DATE_TIME). You can change the format string by registering your own.

java.time.LocalTime

The placeholder is replaced by a formatted Date string (by default DateTimeFormatter.ISO_LOCAL_TIME). You can change the format string by registering your own.

org.wickedsource…​Image

The placeholder is replaced with an inline image.

If a placeholder fails to resolve successfully, Office-Stamper will skip it, the placeholder in the document remains the same as its initial state in the template. You can expand this resolution functionality by implementing your ObjectResolver.

Here’s a code snippet on how to proceed:

class Main {
    public static void main(String... args) {
        // instance of your own ObjectResolver implementation
        var resolver = new StringResolver(YourCustomType.class){
            @Override public String resolve(YourCustomType object){
                return custom.yourCustomProperty(); // or any convoluted method
            }
        };

        var configuration = new DocxStamperConfiguration();
        configuration.addResolver(resolver);
        var stamper = new DocxStamper<>(configuration);
    }
}

Refining SpEL Evaluation Context

At times, you might want to exert more control over how expressions are evaluated. With Office-Stamper, there’s provision for such scenarios. Here’s how:

Implement your own EvaluationContextConfigurer. This allows you to customize Springs StandardEvaluationContext according to your requirements.

Use the following code snippet to register your EvaluationContextConfigurer:

class Main {
    public static void main(String... args) {
        var evalContextConfigurer = new NoOpEvaluationContextConfigurer();
        var configuration = new DocxStamperConfiguration()
            .setEvaluationContextConfigurer(configurer);
        var stamper = new DocxStamper<>(configuration);
    }
}

In this code, NoOpEvaluationContextConfigurer is your custom implementation of EvaluationContextConfigurer. Substitute it with the actual name of your implementation as you use the code above.

This feature empowers you with greater flexibility and enhanced control over the expression evaluation process, fitting Office-Stamper seamlessly into complex scenarios and requirements.

Enhancing the Expression Language with Custom Functions

Office-Stamper lets you add custom functions to the tool’s expression language. For example, if you need specific formats for numbers or dates, you can register such functions which can then be used in the placeholders throughout your template.

Below is a sample code demonstrating how to extend the expression language with a custom function. This particular example adds a function toUppercase(String), enabling you to convert any text in your .docx document to uppercase.

class Main {
    public static void main(String... args) {
        interface UppercaseFunction {
            String toUppercase(String string);
        }

        var configuration = new DocxStamperConfiguration()
            .exposeInterfaceToExpressionLanguage(UppercaseFunction.class, String::toUppercase);
        var stamper = new DocxStamper<>(configuration);
    }
}

Chains of such custom functions can enhance the versatility of Office-Stamper, making it capable of handling complex and unique templating situations.

Processing Comments for Enhanced Functionality

Alongside expression replacement, Office-Stamper presents the feature of processing comments associated with paragraphs in your .docx template. These comments act as directives for manipulating the template. As a standard, the following expressions can be used within comments:

Table 2. Default activated comment processors
Expression in .docx comment Effect

displayParagraphIf(boolean)

The commented paragraph is only displayed in the resulting .docx document if the boolean condition resolves to true.

displayTableRowIf(boolean)

The table row surrounding the commented paragraph is only displayed in the resulting .docx document if the boolean condition resolves to true.

displayTableIf(boolean)

The whole table surrounding the commented paragraph is only displayed in the resulting .docx document if the boolean condition resolves to true.

repeatTableRow(List<Object>)

The table row surrounding the commented paragraph is copied once for each object in the passed-in list. Expressions found in the cells of the table row are evaluated against the object from the list.

repeatDocPart(List<Object>)

Repeat the part of the document surrounded by the comment. The document part is copied once for each object in the passed-in list. Expressions found in the elements of the document part are evaluated against the object from the list. Can be used instead of repeatTableRow and repeatParagraph if you want to repeat more than table rows and paragraphs.

replaceWordWith(expression)

Replaces the commented word (must be a single word) with the value of the given placeholder.

resolveTable(StampTable)

Replace a table (that must have one column and two rows) with the values given by the StampTable. The StampTable contains a list of headers for columns, and a 2-level list of rows containing values for each column.

By default, an exception is thrown if a comment fails to process. However, successfully processed comments are wiped from the document. For additional flexibility, create your own expression within comments by implementing your ICommentProcessor.

Here’s an example of how to create and register a custom comment processor:

class Main {
    public static void main(String... args) {
        // interface defining the methods to expose to the expression language
        interface IYourCommentProcessor {
            void yourComment(String _); // 1+ argument of the type you expect to see in the document
            void yourSecondComment(String _, CustomType _); // theoretically, any number of comment can be added
        }
        class YourCommentProcessor extends BaseCommentProcessor {
            @Override public void commitChanges(WordprocessingMLPackage document) {/*Do something to the document*/}
            @Override public void reset() {/* reset processor state for re-run of the stamper */}
        }
        var commentProcessor = new YourCommentProcessor();
        var configuration = new DocxStamperConfiguration()
                .addCommentProcessor(IYourCommentProcessor.class, commentProcessor);
        var stamper = new DocxStamper<>(configuration);

    }
}

For an in-depth description of how to create a comment processor, see the javadoc of ICommentProcessor.

Conditional and Repetitive Displays within Headers and Footers

The .docx file format does not permit comments within headers or footers. But there’s a workaround in Office-Stamper. If you want to display contents within headers or footers conditionally, or require repetitive elements, all you got to do is :

  1. Craft the expression as you would in a comment.

  2. Encapsulate it with "#{}".

  3. Position it at the starting of the paragraph you intend to manipulate.

The assigned expression will be processed in the same way it would be in a comment, allowing you to maximize template customization.

Remember, this workaround unlocks the power of conditional display and repetition in your document’s headers and footers, enhancing document dynamics.

Graceful Error Handling

In general, DocxStamper employs an UnresolvedExpressionException if there’s a failure in resolving an expression within a document or the associated comments. However, you can modify this behavior.

Follow the given example to silence the exception and keep DocxStamper from failing even when it encounters unresolved expressions:

class Main {
    public static void main(String... args) {
        var configuration = new DocxStamperConfiguration()
                            .setFailOnUnresolvedExpression(false);
        var stamper = new DocxStamper<>(configuration);
    }
}

This customization allows you to control the failure behavior of DocxStamper according to your specific requirements.

Sample Code

The source code contains a set of tests show how to use the features. If you want to run them yourself, clone the repository and run mvn test with the system property -DkeepOutputFile=true so that the resulting .docx documents will not be cleaned up and let you view them. The resulting files will be stored in your local temp folder. Watch the logging output for the exact location of the files).

If you want to have a look at the .docx templates used in the tests, have a look at the sources subfolder in the test folder.

Maven coordinates

To include docx-stamper in your project, you can use the following maven coordinates in your dependency management system: go to last documented version

Note that as of version 1.4.0, you have to provide the dependency to your version of Docx4J yourself:

<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j</artifactId>
    <version>6.1.2</version>
</dependency>

This way, you can choose which version of Docx4J you want to use instead of having it dictated by docx-stamper.

Contribute

If you have an issue or create a comment processor or type resolver that you think deserves to be part of the default distribution, feel free to open an issue or - even better - a pull request with your contribution.