Search in sources :

Example 26 with TemplateProcessingException

use of org.thymeleaf.exceptions.TemplateProcessingException in project thymeleaf-tests by thymeleaf.

the class Spring5Reactive11Test method testDataDrivenEmpty02.

@Test
public void testDataDrivenEmpty02() throws Exception {
    final List<Album> albums = AlbumRepository.findAllAlbums();
    final Context ctx1 = new Context();
    try {
        testTemplate("reactive11", null, ctx1, "reactive11-01", true);
        Assert.assertTrue(false);
    } catch (final TemplateProcessingException e) {
        // When there is no data-driver variable, an exception should be thrown
        Assert.assertTrue(true);
    }
}
Also used : Context(org.thymeleaf.context.Context) Album(org.thymeleaf.spring5.reactive.data.Album) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) Test(org.junit.Test)

Example 27 with TemplateProcessingException

use of org.thymeleaf.exceptions.TemplateProcessingException in project thymeleaf by thymeleaf.

the class TemplateEngine method process.

public final void process(final TemplateSpec templateSpec, final IContext context, final Writer writer) {
    if (!this.initialized) {
        initialize();
    }
    try {
        Validate.notNull(templateSpec, "Template Specification cannot be null");
        Validate.notNull(context, "Context cannot be null");
        Validate.notNull(writer, "Writer cannot be null");
        if (logger.isTraceEnabled()) {
            logger.trace("[THYMELEAF][{}] STARTING PROCESS OF TEMPLATE \"{}\" WITH LOCALE {}", new Object[] { TemplateEngine.threadIndex(), templateSpec, context.getLocale() });
        }
        final long startNanos = System.nanoTime();
        final TemplateManager templateManager = this.configuration.getTemplateManager();
        templateManager.parseAndProcess(templateSpec, context, writer);
        final long endNanos = System.nanoTime();
        if (logger.isTraceEnabled()) {
            logger.trace("[THYMELEAF][{}] FINISHED PROCESS AND OUTPUT OF TEMPLATE \"{}\" WITH LOCALE {}", new Object[] { TemplateEngine.threadIndex(), templateSpec, context.getLocale() });
        }
        if (timerLogger.isTraceEnabled()) {
            final BigDecimal elapsed = BigDecimal.valueOf(endNanos - startNanos);
            final BigDecimal elapsedMs = elapsed.divide(BigDecimal.valueOf(NANOS_IN_SECOND), RoundingMode.HALF_UP);
            timerLogger.trace("[THYMELEAF][{}][{}][{}][{}][{}] TEMPLATE \"{}\" WITH LOCALE {} PROCESSED IN {} nanoseconds (approx. {}ms)", new Object[] { TemplateEngine.threadIndex(), LoggingUtils.loggifyTemplateName(templateSpec.getTemplate()), context.getLocale(), elapsed, elapsedMs, templateSpec, context.getLocale(), elapsed, elapsedMs });
        }
        /*
             * Finally, flush the writer in order to make sure that everything has been written to output
             */
        try {
            writer.flush();
        } catch (final IOException e) {
            throw new TemplateOutputException("An error happened while flushing output writer", templateSpec.getTemplate(), -1, -1, e);
        }
    } catch (final TemplateOutputException e) {
        // We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
        logger.error(String.format("[THYMELEAF][%s] Exception processing template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
        throw e;
    } catch (final TemplateEngineException e) {
        // We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
        logger.error(String.format("[THYMELEAF][%s] Exception processing template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
        throw e;
    } catch (final RuntimeException e) {
        // We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
        logger.error(String.format("[THYMELEAF][%s] Exception processing template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
        throw new TemplateProcessingException("Exception processing template", templateSpec.toString(), e);
    }
}
Also used : TemplateManager(org.thymeleaf.engine.TemplateManager) TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException) IOException(java.io.IOException) BigDecimal(java.math.BigDecimal)

Example 28 with TemplateProcessingException

use of org.thymeleaf.exceptions.TemplateProcessingException in project thymeleaf by thymeleaf.

the class ProcessorTemplateHandler method handleOpenElement.

@Override
public void handleOpenElement(final IOpenElementTag iopenElementTag) {
    /*
         * If processing is stopped, we should queue this for later handling
         * In theory, given the origin of events (parser or cache) should get stopped immediately, this should
         * only happen if a pre-processor is producing additional events.
         */
    if (this.throttleEngine && this.flowController.stopProcessing) {
        queueEvent(iopenElementTag);
        return;
    }
    /*
         * CHECK WHETHER WE ARE GATHERING AN ELEMENT's MODEL
         */
    if (!this.modelController.shouldProcessOpenElement(iopenElementTag)) {
        return;
    }
    /*
         * CAST TO ENGINE-SPECIFIC IMPLEMENTATION, which will ease the handling of the structure during processing
         */
    OpenElementTag openElementTag = OpenElementTag.asEngineOpenElementTag(iopenElementTag);
    /*
         * OBTAIN THE CURRENT SYNTHETIC MODEL (if any). This is needed in case this event was previously being handled,
         * then a gathering process started (as a consequence of the execution of one of its processors), and then
         * once the model was gathered the process started again by handling the first event, which was the one
         * suspended. By obtaining the current gathering model here we can reinitialize all the handling variables and
         * flags to their original state before being suspended.
         */
    final IGatheringModelProcessable currentGatheringModel = obtainCurrentGatheringModel();
    /*
         * If we are resuming an execution after suspending it, we want to retire the register of the element tag
         * that was added by the controller. The reason we want this is that the current tag was already registered
         * by the controller when the execution was suspended, and we don't want it duplicated (nor altered).
         */
    if (currentGatheringModel != null && this.engineContext != null) {
        this.engineContext.setElementTag(null);
    }
    /*
         * FAIL FAST in case this tag has no associated processors and we have no reason to pay attention to it
         * anyway (because of having been suspended).
         */
    if (currentGatheringModel == null && !openElementTag.hasAssociatedProcessors()) {
        this.next.handleOpenElement(openElementTag);
        return;
    }
    /*
         * DECLARE THE STATE VARS NEEDED FOR PROCESSOR EXECUTION. If we are executing the first event of a gathered
         * model, we will just re-initialize to the original variables, the ones we had before suspending.
         */
    final ProcessorExecutionVars vars = (currentGatheringModel == null ? new ProcessorExecutionVars() : currentGatheringModel.initializeProcessorExecutionVars());
    /*
         * GET THE STRUCTURE HANDLERS INTO LOCAL VARS
         */
    final ElementTagStructureHandler tagStructureHandler = this.elementTagStructureHandler;
    final ElementModelStructureHandler modelStructureHandler = this.elementModelStructureHandler;
    /*
         * EXECUTE PROCESSORS
         */
    IElementProcessor processor;
    while (!vars.discardEvent && (processor = vars.processorIterator.next(openElementTag)) != null) {
        tagStructureHandler.reset();
        modelStructureHandler.reset();
        if (processor instanceof IElementTagProcessor) {
            final IElementTagProcessor elementProcessor = ((IElementTagProcessor) processor);
            elementProcessor.process(this.context, openElementTag, tagStructureHandler);
            // Apply any context modifications made by the processor (local vars, inlining, etc.)
            tagStructureHandler.applyContextModifications(this.engineContext);
            // Apply any modifications to the tag itself: new/removed/replace attributes, etc. Note this
            // creates a new tag object because tag objects are immutable.
            openElementTag = tagStructureHandler.applyAttributes(this.attributeDefinitions, openElementTag);
            if (tagStructureHandler.iterateElement) {
                // Initialize the gathering model
                this.modelController.startGatheringIteratedModel(openElementTag, vars, tagStructureHandler.iterVariableName, tagStructureHandler.iterStatusVariableName, tagStructureHandler.iteratedObject);
                // Nothing else to be done by this handler... let's just queue the rest of the events to be iterated
                return;
            } else if (tagStructureHandler.setBodyText) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.setBodyTextProcessable;
                // Add the new Text to the queue
                vars.modelAfter.add(new Text(tagStructureHandler.setBodyTextValue));
                // All the body of the original open tag should be skipped (has just been replaced)
                vars.skipBody = SkipBody.SKIP_ALL;
            } else if (tagStructureHandler.setBodyModel) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.setBodyModelProcessable;
                // Add the new body model to the queue
                vars.modelAfter.addModel(tagStructureHandler.setBodyModelValue);
                // All the body of the original open tag should be skipped (has just been replaced)
                vars.skipBody = SkipBody.SKIP_ALL;
            } else if (tagStructureHandler.insertBeforeModel) {
                // Reset BEFORE model, we need it clean
                vars.modelBefore = resetModel(vars.modelBefore, true);
                // Add model to be passed to this.next BEFORE delegating the event. Note this cannot be processable.
                vars.modelBefore.addModel(tagStructureHandler.insertBeforeModelValue);
            } else if (tagStructureHandler.insertImmediatelyAfterModel) {
                // will not be resetting it because we will be inserting our model at the very beginning of it.
                if (vars.modelAfter == null) {
                    vars.modelAfter = resetModel(vars.modelAfter, true);
                }
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.insertImmediatelyAfterModelProcessable;
                // Insert the new model
                vars.modelAfter.insertModel(0, tagStructureHandler.insertImmediatelyAfterModelValue);
            // No intervention on the body flags - we will not be removing the body, just inserting before it
            } else if (tagStructureHandler.replaceWithText) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.replaceWithTextProcessable;
                // Create the new replacement Text event and add it to the model
                vars.modelAfter.add(new Text(tagStructureHandler.replaceWithTextValue));
                // This tag, its body and its corresponding close tag have to be replaced.
                vars.discardEvent = true;
                vars.skipBody = SkipBody.SKIP_ALL;
                vars.skipCloseTag = true;
            } else if (tagStructureHandler.replaceWithModel) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.replaceWithModelProcessable;
                // Add the new replacement model
                vars.modelAfter.addModel(tagStructureHandler.replaceWithModelValue);
                // This tag, its body and its corresponding close tag have to be replaced.
                vars.discardEvent = true;
                vars.skipBody = SkipBody.SKIP_ALL;
                vars.skipCloseTag = true;
            } else if (tagStructureHandler.removeElement) {
                // Reset model, but only if it already exists
                vars.modelAfter = resetModel(vars.modelAfter, false);
                // We are removing the element (complete with body + close tag). No further processing will be allowed
                vars.discardEvent = true;
                vars.skipBody = SkipBody.SKIP_ALL;
                vars.skipCloseTag = true;
            } else if (tagStructureHandler.removeTags) {
                // No modifications to the queue - it's just the tag that will be removed, not its possible body
                vars.discardEvent = true;
                vars.skipCloseTag = true;
            } else if (tagStructureHandler.removeBody) {
                // Reset model, but only if it already exists
                vars.modelAfter = resetModel(vars.modelAfter, false);
                // We will be only removing the body contents, not the tag itself
                vars.skipBody = SkipBody.SKIP_ALL;
            } else if (tagStructureHandler.removeAllButFirstChild) {
                // Reset model, but only if it already exists
                vars.modelAfter = resetModel(vars.modelAfter, false);
                // This special SkipBody value will allow the first child element (open-body-close or standalone)
                // to be processed, but only that. Once it has been processed, the eventModelController will change
                // this value to SkipBody.SKIP_ELEMENTS.
                // 
                // Note that all non-element child events before and after the first element child event will be
                // processed normally.
                vars.skipBody = SkipBody.PROCESS_ONE_ELEMENT;
            }
        } else if (processor instanceof IElementModelProcessor) {
            if (!vars.processorIterator.lastWasRepeated()) {
                if ((vars.modelBefore != null && vars.modelBefore.size() > 0) || (vars.modelAfter != null && vars.modelAfter.size() > 0)) {
                    throw new TemplateProcessingException("Cannot execute model processor " + processor.getClass().getName() + " as the body " + "of the target element has already been modified by a previously executed processor " + "on the same tag. Model processors cannot execute on already-modified bodies as these " + "might contain unprocessable events (e.g. as a result of a 'th:text' or similar)", openElementTag.getTemplateName(), openElementTag.getLine(), openElementTag.getCol());
                }
                // Set the processor to be executed again, because this time we will just set the "model gathering" mechanism
                vars.processorIterator.setLastToBeRepeated(openElementTag);
                // Initialize the gathering model. This will be concluded (and the gathering model set for
                // processing) at the corresponding close tag.
                this.modelController.startGatheringDelayedModel(openElementTag, vars);
                // Nothing else to be done by this handler... let's just queue the rest of the events in this element
                return;
            }
            /*
                 * This is not the first time we try to execute this processor, which means the model gathering
                 * process has already taken place.
                 */
            // Create the actual Model instance (a clone) that will be passed to the processor to execute on
            final Model gatheredModel = currentGatheringModel.getInnerModel();
            final Model processedModel = new Model(gatheredModel);
            // Execute the processor on the just-created Model
            ((IElementModelProcessor) processor).process(this.context, processedModel, modelStructureHandler);
            // Apply any context modifications made by the processor (local vars, inlining, etc.)
            modelStructureHandler.applyContextModifications(this.engineContext);
            // Reset the skipbody flags so that the processed model can be executed in the same conditions as the original
            currentGatheringModel.resetGatheredSkipFlags();
            /*
                 * Before making any changes and queue the new model for execution, check that it actually is
                 * a "new" model (the processor might have been no-op on the tag and changes might have been
                 * only on the local variables, for example.)
                 */
            if (!gatheredModel.sameAs(processedModel)) {
                /*
                     * Now we will do the exact equivalent to what is performed for an Element Tag processor, when this
                     * returns a result of type "replaceWithModel".
                     */
                // Reset the model
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // Set the model to be executed, and set it to be processable (that is a MUST in this case)
                vars.modelAfter.addModel(processedModel);
                vars.modelAfterProcessable = true;
                // Given we are going to execute the modified model instead of the gathered one, we will set all body
                // skipping flags just as if we had just executed a "replaceWithModel" operation.
                vars.discardEvent = true;
                vars.skipBody = SkipBody.SKIP_ALL;
                vars.skipCloseTag = true;
            }
        } else {
            throw new IllegalStateException("An element has been found with an associated processor of type " + processor.getClass().getName() + " which is neither a Tag Element Processor nor a Model Element Processor.");
        }
    }
    /*
         * QUEUE MODEL HANDLING (IF WE ARE THROTTLING)
         */
    if (this.throttleEngine && ((vars.modelAfter != null && vars.modelAfter.size() > 0) || (vars.modelBefore != null && vars.modelBefore.size() > 0))) {
        queueProcessable(new OpenElementTagModelProcessable(openElementTag, vars, this.modelController, this.flowController, this, this.next));
        return;
    }
    /*
         * PROCESS THE QUEUE BEFORE DELEGATING, if specified to do so
         */
    if (vars.modelBefore != null) {
        // This is never processable
        vars.modelBefore.process(this.next);
    }
    /*
         * PROCESS THE REST OF THE HANDLER CHAIN and INCREASE THE MODEL LEVEL RIGHT AFTERWARDS
         */
    if (!vars.discardEvent) {
        this.next.handleOpenElement(openElementTag);
    }
    /*
         * PROCESS THE QUEUE, launching all the queued events. Note executing the queue after increasing the model
         * level makes sense even if what the queue contains is a replacement for the complete element (including open
         * and close tags), because that way whatever comes in the queue will be encapsulated in a different model level
         * and its internal open/close tags should not affect the correct delimitation of this block.
         */
    if (vars.modelAfter != null) {
        vars.modelAfter.process(vars.modelAfterProcessable ? this : this.next);
    }
    /*
         * SET BODY TO BE SKIPPED, if required. Importantly, this has to be done AFTER executing the queue
         */
    this.modelController.skip(vars.skipBody, vars.skipCloseTag);
}
Also used : IElementTagProcessor(org.thymeleaf.processor.element.IElementTagProcessor) IText(org.thymeleaf.model.IText) IOpenElementTag(org.thymeleaf.model.IOpenElementTag) IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) IElementModelProcessor(org.thymeleaf.processor.element.IElementModelProcessor) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException)

Example 29 with TemplateProcessingException

use of org.thymeleaf.exceptions.TemplateProcessingException in project thymeleaf by thymeleaf.

the class ThrottledTemplateProcessor method process.

private int process(final int maxOutput, final String outputType) {
    int writtenCount = 0;
    try {
        if (this.allProcessingFinished || maxOutput == 0) {
            // No bytes written
            return 0;
        }
        if (logger.isTraceEnabled()) {
            logger.trace("[THYMELEAF][{}] Starting throttled process (limit:{} {}) of template \"{}\" with locale {}", new Object[] { TemplateEngine.threadIndex(), Integer.valueOf(maxOutput), outputType, this.templateSpec, this.context.getLocale() });
        }
        final long startNanos = System.nanoTime();
        // Save the initial written count so that we can know at the end how many bytes were written
        final int initialWrittenCount = this.writer.getWrittenCount();
        // Set the new limit for the writer (might provoke overflow being processed)
        this.writer.allow(maxOutput);
        // Maybe by processing all overflow we just finished
        if (!computeFinish() && !this.writer.isStopped()) {
            if (this.flowController.processorTemplateHandlerPending) {
                this.processorTemplateHandler.handlePending();
            }
            if (!computeFinish() && !this.writer.isStopped()) {
                this.offset += this.templateModel.process(this.templateHandler, this.offset, this.flowController);
                if (this.offset == this.templateModel.size()) {
                    EngineContextManager.disposeEngineContext(this.context);
                    this.eventProcessingFinished = true;
                    computeFinish();
                }
            }
        }
        final long endNanos = System.nanoTime();
        /*
             * Finally, flush the writer in order to make sure that everything has been written to output
             */
        try {
            this.writer.flush();
        } catch (final IOException e) {
            throw new TemplateOutputException("An error happened while flushing output writer", templateSpec.getTemplate(), -1, -1, e);
        }
        writtenCount = this.writer.getWrittenCount() - initialWrittenCount;
        if (logger.isTraceEnabled()) {
            logger.trace("[THYMELEAF][{}] Finished throttled process (limit:{} {}, output: {} {}) of template \"{}\" with locale {}", new Object[] { TemplateEngine.threadIndex(), Integer.valueOf(maxOutput), outputType, Integer.valueOf(writtenCount), outputType, this.templateSpec, this.context.getLocale() });
        }
        if (timerLogger.isTraceEnabled()) {
            final BigDecimal elapsed = BigDecimal.valueOf(endNanos - startNanos);
            final BigDecimal elapsedMs = elapsed.divide(BigDecimal.valueOf(NANOS_IN_SECOND), RoundingMode.HALF_UP);
            timerLogger.trace("[THYMELEAF][{}][{}][{}][{}][{}] TEMPLATE \"{}\" WITH LOCALE {} PROCESSED (THROTTLED, LIMIT:{} {}, OUTPUT: {} {}) IN {} nanoseconds (approx. {}ms)", new Object[] { TemplateEngine.threadIndex(), LoggingUtils.loggifyTemplateName(this.templateSpec.getTemplate()), this.context.getLocale(), elapsed, elapsedMs, this.templateSpec, this.context.getLocale(), Integer.valueOf(maxOutput), outputType, Integer.valueOf(writtenCount), outputType, elapsed, elapsedMs });
        }
    } catch (final TemplateOutputException e) {
        this.eventProcessingFinished = true;
        this.allProcessingFinished = true;
        // We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
        logger.error(String.format("[THYMELEAF][%s] Exception processing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), this.templateSpec, e.getMessage() }), e);
        throw e;
    } catch (final TemplateEngineException e) {
        this.eventProcessingFinished = true;
        this.allProcessingFinished = true;
        // We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
        logger.error(String.format("[THYMELEAF][%s] Exception processing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), this.templateSpec, e.getMessage() }), e);
        throw e;
    } catch (final Exception e) {
        this.eventProcessingFinished = true;
        this.allProcessingFinished = true;
        // We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
        logger.error(String.format("[THYMELEAF][%s] Exception processing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), this.templateSpec, e.getMessage() }), e);
        throw new TemplateProcessingException("Exception processing throttled template", this.templateSpec.toString(), e);
    }
    reportFinish(outputType);
    return writtenCount;
}
Also used : TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException) IOException(java.io.IOException) BigDecimal(java.math.BigDecimal) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) IOException(java.io.IOException) TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException)

Example 30 with TemplateProcessingException

use of org.thymeleaf.exceptions.TemplateProcessingException in project thymeleaf by thymeleaf.

the class Model method toString.

@Override
public final String toString() {
    try {
        final Writer writer = new FastStringWriter();
        write(writer);
        return writer.toString();
    } catch (final IOException e) {
        throw new TemplateProcessingException("Error while creating String representation of model");
    }
}
Also used : FastStringWriter(org.thymeleaf.util.FastStringWriter) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) IOException(java.io.IOException) FastStringWriter(org.thymeleaf.util.FastStringWriter) Writer(java.io.Writer)

Aggregations

TemplateProcessingException (org.thymeleaf.exceptions.TemplateProcessingException)45 BigDecimal (java.math.BigDecimal)12 IEngineConfiguration (org.thymeleaf.IEngineConfiguration)8 IStandardExpression (org.thymeleaf.standard.expression.IStandardExpression)6 IOException (java.io.IOException)5 ITemplateContext (org.thymeleaf.context.ITemplateContext)4 Writer (java.io.Writer)3 Test (org.junit.Test)3 Context (org.thymeleaf.context.Context)3 AttributeName (org.thymeleaf.engine.AttributeName)3 TemplateEngineException (org.thymeleaf.exceptions.TemplateEngineException)3 TemplateInputException (org.thymeleaf.exceptions.TemplateInputException)3 TemplateOutputException (org.thymeleaf.exceptions.TemplateOutputException)3 FastStringWriter (org.thymeleaf.util.FastStringWriter)3 DataBuffer (org.springframework.core.io.buffer.DataBuffer)2 IEngineContext (org.thymeleaf.context.IEngineContext)2 TemplateManager (org.thymeleaf.engine.TemplateManager)2 IAttribute (org.thymeleaf.model.IAttribute)2 IOpenElementTag (org.thymeleaf.model.IOpenElementTag)2 IProcessableElementTag (org.thymeleaf.model.IProcessableElementTag)2