DocxStamperConfiguration.java
package pro.verron.officestamper.core;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import pro.verron.officestamper.api.*;
import pro.verron.officestamper.api.CustomFunction.NeedsBiFunctionImpl;
import pro.verron.officestamper.api.CustomFunction.NeedsFunctionImpl;
import pro.verron.officestamper.api.CustomFunction.NeedsTriFunctionImpl;
import pro.verron.officestamper.core.functions.BiFunctionBuilder;
import pro.verron.officestamper.core.functions.FunctionBuilder;
import pro.verron.officestamper.core.functions.TriFunctionBuilder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
/// The [DocxStamperConfiguration] class represents the configuration for the [DocxStamper] class.
///
/// It provides methods to customize the behavior of the stamper.
///
/// @author Joseph Verron
/// @author Tom Hombergs
/// @version ${version}
/// @since 1.0.3
public class DocxStamperConfiguration
implements OfficeStamperConfiguration {
private final Map<Class<?>, CommentProcessorFactory> commentProcessors;
private final List<ObjectResolver> resolvers;
private final Map<Class<?>, Object> expressionFunctions;
private final List<PreProcessor> preprocessors;
private final List<PostProcessor> postprocessors;
private final List<CustomFunction> functions;
private EvaluationContextFactory evaluationContextFactory;
private ExpressionParser expressionParser;
private ExceptionResolver exceptionResolver;
/// Constructs a new instance of the [DocxStamperConfiguration] class and initializes its default configuration
/// settings.
///
/// This constructor sets up internal structures and default behaviors for managing document stamping
/// configurations, including:
/// - Initializing collections for processors, resolvers, and functions.
/// - Setting default values for expression handling and evaluation.
/// - Creating and configuring a default `SpelParserConfiguration`.
/// - Establishing resolvers and exception handling strategies.
///
/// @param evaluationContextFactory the factory used to create [EvaluationContext] instances.
/// @param exceptionResolver the exception resolver to use for handling exceptions during stamping.
public DocxStamperConfiguration(
EvaluationContextFactory evaluationContextFactory,
ExceptionResolver exceptionResolver
) {
this.commentProcessors = new HashMap<>();
this.resolvers = new ArrayList<>();
this.expressionFunctions = new HashMap<>();
this.preprocessors = new ArrayList<>();
this.postprocessors = new ArrayList<>();
this.functions = new ArrayList<>();
this.evaluationContextFactory = evaluationContextFactory;
this.expressionParser = new SpelExpressionParser();
this.exceptionResolver = exceptionResolver;
}
/// Exposes all methods of a given interface to the expression language.
///
/// @param interfaceClass the interface holding methods to expose in the expression language.
/// @param implementation the implementation to call to evaluate invocations of those methods, it must
/// implement the mentioned interface.
///
/// @return a [DocxStamperConfiguration] object
@Override
public DocxStamperConfiguration exposeInterfaceToExpressionLanguage(
Class<?> interfaceClass,
Object implementation
) {
this.expressionFunctions.put(interfaceClass, implementation);
return this;
}
/// Registers the specified [CommentProcessor] as an implementation of the specified interface.
///
/// @param interfaceClass the interface, implemented by the commentProcessor.
/// @param commentProcessorFactory the commentProcessor factory generating instances of the specified
/// interface.
///
/// @return a [DocxStamperConfiguration] object
@Override
public DocxStamperConfiguration addCommentProcessor(
Class<?> interfaceClass,
CommentProcessorFactory commentProcessorFactory
) {
this.commentProcessors.put(interfaceClass, commentProcessorFactory);
return this;
}
/// Adds a preprocessor to the configuration.
///
/// @param preprocessor the preprocessor to add.
@Override
public void addPreprocessor(PreProcessor preprocessor) {
preprocessors.add(preprocessor);
}
/// Retrieves the configured [EvaluationContextFactory] instance.
///
/// @return an instance of [EvaluationContextFactory] used for creating evaluation contexts
@Override
public EvaluationContextFactory getEvaluationContextFactory() {
return evaluationContextFactory;
}
/// Sets the [EvaluationContextFactory] which creates Spring [EvaluationContext] instances used for evaluating
/// expressions in comments and text.
///
/// @param evaluationContextFactory the factory to use.
///
/// @return the configuration object for chaining.
@Override
public DocxStamperConfiguration setEvaluationContextFactory(EvaluationContextFactory evaluationContextFactory) {
this.evaluationContextFactory = evaluationContextFactory;
return this;
}
/// Retrieves the mapping of expression function classes to their corresponding function instances.
///
/// @return a map where the keys are classes representing the function types, and the values are the function
/// instances.
@Override
public Map<Class<?>, Object> getExpressionFunctions() {
return expressionFunctions;
}
/// Retrieves the map of comment processors associated with specific classes.
///
/// @return a map where the key is the class associated with a specific type of placeholder, and the value is a
/// function that creates a [CommentProcessor] for that placeholder.
@Override
public Map<Class<?>, CommentProcessorFactory> getCommentProcessors() {
return commentProcessors;
}
/// Retrieves the list of preprocessors.
///
/// @return a list of [PreProcessor] objects.
@Override
public List<PreProcessor> getPreprocessors() {
return preprocessors;
}
/// Retrieves the list of object resolvers.
///
/// @return a list of [ObjectResolver] instances.
@Override
public List<ObjectResolver> getResolvers() {
return resolvers;
}
/// Sets resolvers for resolving objects in the [DocxStamperConfiguration].
///
/// This method is the evolution of the method [#addResolver(ObjectResolver)], and the order in which the resolvers
/// are ordered is determinant; the first resolvers in the list will be tried first.
///
/// If a fallback resolver is desired, it should be placed last in the list.
///
/// @param resolvers The list of [ObjectResolver] to be set.
///
/// @return the configuration object for chaining.
@Override
public DocxStamperConfiguration setResolvers(List<ObjectResolver> resolvers) {
this.resolvers.clear();
this.resolvers.addAll(resolvers);
return this;
}
/// Adds a resolver to the list of resolvers in the [DocxStamperConfiguration] object.
///
/// Resolvers are used to resolve objects during the stamping process.
///
/// @param resolver The resolver to be added.
///
/// @return The modified [DocxStamperConfiguration] object, with the resolver added to the beginning of the resolver
/// list.
@Override
public DocxStamperConfiguration addResolver(ObjectResolver resolver) {
resolvers.addFirst(resolver);
return this;
}
/// Retrieves the exception resolver.
///
/// @return the current instance of [ExceptionResolver].
@Override
public ExceptionResolver getExceptionResolver() {
return exceptionResolver;
}
/// Configures the exception resolver for the [DocxStamperConfiguration].
///
/// @param exceptionResolver the [ExceptionResolver] to handle exceptions during processing
///
/// @return the current instance of [DocxStamperConfiguration]
@Override
public DocxStamperConfiguration setExceptionResolver(ExceptionResolver exceptionResolver) {
this.exceptionResolver = exceptionResolver;
return this;
}
/// Retrieves a list of custom functions.
///
/// @return a List containing [CustomFunction] objects.
@Override
public List<CustomFunction> customFunctions() {
return functions;
}
/// Adds a custom function to the system, allowing integration of user-defined functionality.
///
/// @param name The name of the custom function being added. This is used as the identifier for the function
/// and must be unique across all defined functions.
/// @param implementation A [Supplier] functional interface that provides the implementation of the custom
/// function. When the function is called, the supplier's get method will be executed to return the result
/// of the function.
@Override
public void addCustomFunction(String name, Supplier<?> implementation) {
this.addCustomFunction(new CustomFunction(name, List.of(), args -> implementation.get()));
}
/// Adds a custom function to the list of functions.
///
/// @param function the [CustomFunction] object to be added
public void addCustomFunction(CustomFunction function) {
this.functions.add(function);
}
/// Adds a custom function to the context with the specified name and type.
///
/// @param name the name of the custom function
/// @param class0 the class type of the custom function
/// @param <T> the type of the input parameter
///
/// @return an instance of [NeedsFunctionImpl] configured with the custom function
@Override
public <T> NeedsFunctionImpl<T> addCustomFunction(String name, Class<T> class0) {
return new FunctionBuilder<>(this, name, class0);
}
/// Adds a custom function with the specified name and input types.
///
/// @param name the name of the custom function to be added
/// @param class0 the class type of the first input parameter of the custom function.
/// @param class1 the class type of the second input parameter of the custom function.
/// @param <T> the type of the first input parameter
/// @param <U> the type of the second input parameter
///
/// @return an instance of [NeedsBiFunctionImpl] for further configuration or usage of the custom function.
@Override
public <T, U> NeedsBiFunctionImpl<T, U> addCustomFunction(String name, Class<T> class0, Class<U> class1) {
return new BiFunctionBuilder<>(this, name, class0, class1);
}
/// Adds a custom function to the current context by defining its name, and the classes associated with its argument
/// types.
///
/// @param name the name to assign to the custom function
/// @param class0 the class of the first argument type
/// @param class1 the class of the second argument type
/// @param class2 the class of the third argument type
/// @param <T> the type of the first argument
/// @param <U> the type of the second argument
/// @param <V> the type of the third argument
///
/// @return an instance of [NeedsTriFunctionImpl] indicating the custom function implementation and usage context.
@Override
public <T, U, V> NeedsTriFunctionImpl<T, U, V> addCustomFunction(
String name,
Class<T> class0,
Class<U> class1,
Class<V> class2
) {
return new TriFunctionBuilder<>(this, name, class0, class1, class2);
}
/// Retrieves the list of postprocessors.
///
/// @return a List of [PostProcessor] objects.
@Override
public List<PostProcessor> getPostprocessors() {
return postprocessors;
}
/// Adds a given postprocessor to the list of postprocessors.
///
/// @param postprocessor the [PostProcessor] instance to be added
@Override
public void addPostprocessor(PostProcessor postprocessor) {
postprocessors.add(postprocessor);
}
@Override
public ExpressionParser getExpressionParser() {
return expressionParser;
}
/// Sets the expression parser used for expression evaluation.
///
/// Note that the provided parser will be used for all expressions in the document, including expressions in
/// comments. If you use SpEL, construct a `SpelExpressionParser` (optionally with a `SpelParserConfiguration`) and
/// pass it here.
///
/// @param expressionParser the parser to use.
///
/// @return the configuration object for chaining.
@Override
public DocxStamperConfiguration setExpressionParser(ExpressionParser expressionParser) {
this.expressionParser = expressionParser;
return this;
}
/// Resets all processors in the configuration.
public void resetCommentProcessors() {
this.commentProcessors.clear();
}
/// Resets all resolvers in the configuration.
public void resetResolvers() {
this.resolvers.clear();
}
}