DocxStamper.java

1
package pro.verron.officestamper.core;
2
3
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
4
import org.docx4j.openpackaging.parts.Part;
5
import org.docx4j.wml.ContentAccessor;
6
import pro.verron.officestamper.api.*;
7
8
import java.util.ArrayList;
9
import java.util.List;
10
import java.util.Map;
11
12
import static org.docx4j.openpackaging.parts.relationships.Namespaces.FOOTER;
13
import static org.docx4j.openpackaging.parts.relationships.Namespaces.HEADER;
14
15
/// The [DocxStamper] class is an implementation of the [OfficeStamper] interface used to stamp DOCX templates with a
16
/// context object and write the result to an output stream.
17
///
18
/// @author Tom Hombergs
19
/// @author Joseph Verron
20
/// @version ${version}
21
/// @since 1.0.0
22
public class DocxStamper
23
        implements OfficeStamper<WordprocessingMLPackage> {
24
25
    private final List<PreProcessor> preprocessors;
26
    private final List<PostProcessor> postprocessors;
27
    private final EngineFactory engineFactory;
28
    private final EvaluationContextFactory contextFactory;
29
    private final Map<Class<?>, Object> interfaceFunctions;
30
    private final List<CustomFunction> customFunctions;
31
    private final Map<Class<?>, CommentProcessorFactory> commentProcessors;
32
33
    /// Creates new [DocxStamper] with the given configuration.
34
    ///
35
    /// @param configuration the configuration to use for this [DocxStamper].
36
    public DocxStamper(OfficeStamperConfiguration configuration) {
37
        this.contextFactory = configuration.getEvaluationContextFactory();
38
        this.interfaceFunctions = configuration.getExpressionFunctions();
39
        this.customFunctions = configuration.customFunctions();
40
        this.commentProcessors = configuration.getCommentProcessors();
41
        this.engineFactory = processorContext -> {
42
            var expressionParser = configuration.getExpressionParser();
43
            var exceptionResolver = configuration.getExceptionResolver();
44
            var resolvers = configuration.getResolvers();
45
            var registry = new ObjectResolverRegistry(resolvers);
46 1 1. lambda$new$0 : replaced return value with null for pro/verron/officestamper/core/DocxStamper::lambda$new$0 → KILLED
            return new Engine(expressionParser, exceptionResolver, registry, processorContext);
47
        };
48
        this.preprocessors = new ArrayList<>(configuration.getPreprocessors());
49
        this.postprocessors = new ArrayList<>(configuration.getPostprocessors());
50
    }
51
52
    /// Reads in a .docx template and "stamps" it, using the specified context object to
53
    /// fill out any expressions it finds.
54
    ///
55
    /// In the .docx template you have the following options to influence the "stamping" process:
56
    ///   - Use expressions like `${name}` or `${person.isOlderThan(18)}` in the template's text. These expressions are
57
    /// resolved against the contextRoot object you pass into this method and are replaced by the results.
58
    ///   - Use comments within the .docx template to mark certain paragraphs to be manipulated.
59
    ///
60
    /// Within comments, you can put expressions in which you can use the following methods by default:
61
    ///   - `displayParagraphIf(boolean)` to conditionally display paragraphs or not
62
    ///   - `displayTableRowIf(boolean)` to conditionally display table rows or not
63
    ///   - `displayTableIf(boolean)` to conditionally display whole tables or not
64
    ///   - `repeatTableRow(List<Object>)` to create a new table row for each object in the list and resolve expressions
65
    /// within the table cells against one of the objects within the list.
66
    ///
67
    /// If you need a wider vocabulary of methods available in the comments, you can create your own [CommentProcessor]
68
    /// and register it via [OfficeStamperConfiguration#addCommentProcessor(Class, CommentProcessorFactory)].
69
    ///
70
    /// @param document the .docx template to stamp
71
    /// @param contextRoot the context object to use for stamping
72
    ///
73
    /// @return the stamped document
74
    @Override
75
    public WordprocessingMLPackage stamp(WordprocessingMLPackage document, Object contextRoot) {
76 1 1. stamp : removed call to pro/verron/officestamper/core/DocxStamper::preprocess → KILLED
        preprocess(document);
77 1 1. stamp : removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED
        process(document, contextRoot);
78 1 1. stamp : removed call to pro/verron/officestamper/core/DocxStamper::postprocess → TIMED_OUT
        postprocess(document);
79 1 1. stamp : replaced return value with null for pro/verron/officestamper/core/DocxStamper::stamp → KILLED
        return document;
80
    }
81
82
    private void preprocess(WordprocessingMLPackage document) {
83 2 1. preprocess : removed call to java/util/List::forEach → KILLED
2. lambda$preprocess$0 : removed call to pro/verron/officestamper/api/PreProcessor::process → KILLED
        preprocessors.forEach(processor -> processor.process(document));
84
    }
85
86
    private void process(WordprocessingMLPackage document, Object contextRoot) {
87
        var mainDocumentPart = document.getMainDocumentPart();
88
        var mainPart = new TextualDocxPart(document, mainDocumentPart, mainDocumentPart);
89 1 1. process : removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED
        process(mainPart, contextRoot);
90
91
        var relationshipsPart = mainDocumentPart.getRelationshipsPart();
92
        for (var relationship : relationshipsPart.getRelationshipsByType(HEADER)) {
93
            Part part1 = relationshipsPart.getPart(relationship);
94
            TextualDocxPart textualDocxPart = new TextualDocxPart(document, part1, (ContentAccessor) part1);
95 1 1. process : removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED
            process(textualDocxPart, contextRoot);
96
        }
97
98
        for (var relationship : relationshipsPart.getRelationshipsByType(FOOTER)) {
99
            Part part = relationshipsPart.getPart(relationship);
100
            TextualDocxPart textualDocxPart = new TextualDocxPart(document, part, (ContentAccessor) part);
101 1 1. process : removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED
            process(textualDocxPart, contextRoot);
102
        }
103
    }
104
105
    private void postprocess(WordprocessingMLPackage document) {
106 2 1. postprocess : removed call to java/util/List::forEach → TIMED_OUT
2. lambda$postprocess$0 : removed call to pro/verron/officestamper/api/PostProcessor::process → TIMED_OUT
        postprocessors.forEach(processor -> processor.process(document));
107
    }
108
109
    private void process(DocxPart part, Object contextRoot) {
110
        var contextTree = new ContextRoot(contextRoot);
111
        var iterator = DocxHook.ofHooks(part::content, part);
112 1 1. process : negated conditional → KILLED
        while (iterator.hasNext()) {
113
            var hook = iterator.next();
114
            var officeStamperContextFactory = new OfficeStamperEvaluationContextFactory(customFunctions,
115
                    commentProcessors,
116
                    interfaceFunctions,
117
                    contextFactory);
118 1 1. process : negated conditional → TIMED_OUT
            if (hook.run(engineFactory, contextTree, officeStamperContextFactory)) {
119 1 1. process : removed call to pro/verron/officestamper/utils/iterator/ResetableIterator::reset → TIMED_OUT
                iterator.reset();
120
            }
121
        }
122
    }
123
124
}

Mutations

46

1.1
Location : lambda$new$0
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
replaced return value with null for pro/verron/officestamper/core/DocxStamper::lambda$new$0 → KILLED

76

1.1
Location : stamp
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
removed call to pro/verron/officestamper/core/DocxStamper::preprocess → KILLED

77

1.1
Location : stamp
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED

78

1.1
Location : stamp
Killed by : none
removed call to pro/verron/officestamper/core/DocxStamper::postprocess → TIMED_OUT

79

1.1
Location : stamp
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[method:testTableOfContent()]
replaced return value with null for pro/verron/officestamper/core/DocxStamper::stamp → KILLED

83

1.1
Location : preprocess
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
removed call to java/util/List::forEach → KILLED

2.2
Location : lambda$preprocess$0
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
removed call to pro/verron/officestamper/api/PreProcessor::process → KILLED

89

1.1
Location : process
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED

95

1.1
Location : process
Killed by : pro.verron.officestamper.test.HeaderAndFooterTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.HeaderAndFooterTest]/[test-template:placeholders(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED

101

1.1
Location : process
Killed by : pro.verron.officestamper.test.HeaderAndFooterTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.HeaderAndFooterTest]/[test-template:placeholders(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
removed call to pro/verron/officestamper/core/DocxStamper::process → KILLED

106

1.1
Location : postprocess
Killed by : none
removed call to java/util/List::forEach → TIMED_OUT

2.2
Location : lambda$postprocess$0
Killed by : none
removed call to pro/verron/officestamper/api/PostProcessor::process → TIMED_OUT

112

1.1
Location : process
Killed by : pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.FailOnUnresolvedPlaceholderTest]/[test-template:fails(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#1]
negated conditional → KILLED

118

1.1
Location : process
Killed by : none
negated conditional → TIMED_OUT

119

1.1
Location : process
Killed by : none
removed call to pro/verron/officestamper/utils/iterator/ResetableIterator::reset → TIMED_OUT

Active mutators

Tests examined


Report generated by PIT 1.22.0