PlaceholderReplacer.java
package pro.verron.officestamper.core;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.*;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelParseException;
import pro.verron.officestamper.api.*;
import pro.verron.officestamper.utils.WmlFactory;
import static pro.verron.officestamper.utils.WmlFactory.newBr;
/// Replaces expressions in a document with the values provided by the [ExpressionResolver].
///
/// @author Joseph Verron
/// @author Tom Hombergs
/// @version ${version}
/// @since 1.0.0
public class PlaceholderReplacer
implements ParagraphPlaceholderReplacer {
private final ExpressionResolver resolver;
private final ObjectResolverRegistry registry;
private final Placeholder lineBreakPlaceholder;
private final ExceptionResolver exceptionResolver;
/// Constructor for PlaceholderReplacer.
///
/// @param registry the registry containing all available type resolvers.
/// @param resolver the expression resolver used to resolve expressions in the document.
/// @param linebreakPlaceholder if set to a non-null value,
/// all occurrences of this placeholder will be
/// replaced with a line break.
public PlaceholderReplacer(
ObjectResolverRegistry registry,
ExpressionResolver resolver,
Placeholder linebreakPlaceholder,
ExceptionResolver exceptionResolver
) {
this.registry = registry;
this.resolver = resolver;
this.lineBreakPlaceholder = linebreakPlaceholder;
this.exceptionResolver = exceptionResolver;
}
/// Finds expressions in a document and resolves them against the specified context object.
/// The resolved values will then replace the expressions in the document.
///
/// @param expressionContext the context root
public void resolveExpressions(DocxPart document, Object expressionContext) {
document.streamParagraphs()
.forEach(paragraph -> resolveExpressionsForParagraph(document, paragraph, expressionContext));
}
/// Finds expressions in the given paragraph and replaces them with the values provided by the expression resolver.
///
/// @param docxPart the document in which to replace all expressions.
/// @param paragraph the paragraph in which to replace expressions.
/// @param context the context root
@Override public void resolveExpressionsForParagraph(
DocxPart docxPart,
Paragraph paragraph,
Object context
) {
var expressions = Placeholders.findVariables(paragraph);
for (var expression : expressions) {
var replacement = resolve(docxPart, context, expression);
paragraph.replace(expression, replacement);
}
paragraph.replace(lineBreakPlaceholder, newBr());
}
private R resolve(DocxPart docxPart, Object context, Placeholder placeholder) {
try {
resolver.setContext(context);
var resolution = resolver.resolve(placeholder);
return registry.resolve(docxPart, placeholder, resolution);
} catch (SpelEvaluationException
| SpelParseException
| OfficeStamperException e) {
var message = "Expression %s could not be resolved against context of type %s"
.formatted(placeholder.expression(), context.getClass().getSimpleName());
var resolution = exceptionResolver.resolve(placeholder, message, e);
return WmlFactory.newRun(resolution);
}
}
/// Resolves expressions in the given paragraph using the specified context and document.
/// This method is deprecated and should not be called. Calling it will result in an exception.
///
/// @param paragraph the paragraph in which expressions were expected to be resolved
/// @param context the context object used for expression resolution
/// @param document the WordprocessingMLPackage document associated with the paragraph
@Override
public void resolveExpressionsForParagraph(Paragraph paragraph, Object context, WordprocessingMLPackage document) {
throw new OfficeStamperException("Should not be called, since deprecated");
}
}