Search in sources :

Example 36 with IEngineConfiguration

use of org.thymeleaf.IEngineConfiguration in project thymeleaf-tests by thymeleaf.

the class DialectProcessWrappingTest method testDialectWrapping.

@Test
public void testDialectWrapping() throws Exception {
    final Dialect01 dialect01 = new Dialect01();
    final TemplateEngine templateEngine = new TemplateEngine();
    templateEngine.setDialect(dialect01);
    final IEngineConfiguration config = templateEngine.getConfiguration();
    final List<IElementProcessor> elementProcessors = new ArrayList<IElementProcessor>(config.getElementProcessors(TemplateMode.HTML));
    final List<ICDATASectionProcessor> cdataSectionProcessors = new ArrayList<ICDATASectionProcessor>(config.getCDATASectionProcessors(TemplateMode.HTML));
    final List<ICommentProcessor> commentProcessors = new ArrayList<ICommentProcessor>(config.getCommentProcessors(TemplateMode.HTML));
    final List<IDocTypeProcessor> docTypeProcessors = new ArrayList<IDocTypeProcessor>(config.getDocTypeProcessors(TemplateMode.HTML));
    final List<IProcessingInstructionProcessor> processingInstructionProcessors = new ArrayList<IProcessingInstructionProcessor>(config.getProcessingInstructionProcessors(TemplateMode.HTML));
    final List<ITemplateBoundariesProcessor> templateBoundariesProcessors = new ArrayList<ITemplateBoundariesProcessor>(config.getTemplateBoundariesProcessors(TemplateMode.HTML));
    final List<ITextProcessor> textProcessors = new ArrayList<ITextProcessor>(config.getTextProcessors(TemplateMode.HTML));
    final List<IXMLDeclarationProcessor> xmlDeclarationProcessors = new ArrayList<IXMLDeclarationProcessor>(config.getXMLDeclarationProcessors(TemplateMode.HTML));
    Assert.assertEquals(2, elementProcessors.size());
    Assert.assertEquals(1, cdataSectionProcessors.size());
    Assert.assertEquals(1, commentProcessors.size());
    Assert.assertEquals(1, docTypeProcessors.size());
    Assert.assertEquals(1, processingInstructionProcessors.size());
    Assert.assertEquals(1, templateBoundariesProcessors.size());
    Assert.assertEquals(1, textProcessors.size());
    Assert.assertEquals(1, xmlDeclarationProcessors.size());
    // We will use the class names because the classes are package-protected
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$ElementModelProcessorWrapper", elementProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper", elementProcessors.get(1).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$CDATASectionProcessorWrapper", cdataSectionProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$CommentProcessorWrapper", commentProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$DocTypeProcessorWrapper", docTypeProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$ProcessingInstructionProcessorWrapper", processingInstructionProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$TemplateBoundariesProcessorWrapper", templateBoundariesProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$TextProcessorWrapper", textProcessors.get(0).getClass().getName());
    Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$XMLDeclarationProcessorWrapper", xmlDeclarationProcessors.get(0).getClass().getName());
    Assert.assertEquals(100, elementProcessors.get(0).getPrecedence());
    Assert.assertEquals(110, elementProcessors.get(1).getPrecedence());
    Assert.assertEquals(100, cdataSectionProcessors.get(0).getPrecedence());
    Assert.assertEquals(100, commentProcessors.get(0).getPrecedence());
    Assert.assertEquals(100, docTypeProcessors.get(0).getPrecedence());
    Assert.assertEquals(100, processingInstructionProcessors.get(0).getPrecedence());
    Assert.assertEquals(100, templateBoundariesProcessors.get(0).getPrecedence());
    Assert.assertEquals(100, textProcessors.get(0).getPrecedence());
    Assert.assertEquals(100, xmlDeclarationProcessors.get(0).getPrecedence());
}
Also used : IEngineConfiguration(org.thymeleaf.IEngineConfiguration) ITextProcessor(org.thymeleaf.processor.text.ITextProcessor) IProcessingInstructionProcessor(org.thymeleaf.processor.processinginstruction.IProcessingInstructionProcessor) ArrayList(java.util.ArrayList) ITemplateBoundariesProcessor(org.thymeleaf.processor.templateboundaries.ITemplateBoundariesProcessor) Dialect01(org.thymeleaf.dialect.dialectwrapping.Dialect01) IDocTypeProcessor(org.thymeleaf.processor.doctype.IDocTypeProcessor) IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) ICommentProcessor(org.thymeleaf.processor.comment.ICommentProcessor) TemplateEngine(org.thymeleaf.TemplateEngine) IXMLDeclarationProcessor(org.thymeleaf.processor.xmldeclaration.IXMLDeclarationProcessor) ICDATASectionProcessor(org.thymeleaf.processor.cdatasection.ICDATASectionProcessor) Test(org.junit.Test)

Example 37 with IEngineConfiguration

use of org.thymeleaf.IEngineConfiguration in project thymeleaf by thymeleaf.

the class EachUtils method parseEach.

public static Each parseEach(final IExpressionContext context, final String input) {
    Validate.notNull(context, "Context cannot be null");
    Validate.notNull(input, "Input cannot be null");
    final String preprocessedInput = StandardExpressionPreprocessor.preprocess(context, input);
    final IEngineConfiguration configuration = context.getConfiguration();
    if (configuration != null) {
        final Each cachedEach = ExpressionCache.getEachFromCache(configuration, preprocessedInput);
        if (cachedEach != null) {
            return cachedEach;
        }
    }
    final Each each = internalParseEach(preprocessedInput.trim());
    if (each == null) {
        throw new TemplateProcessingException("Could not parse as each: \"" + input + "\"");
    }
    if (configuration != null) {
        ExpressionCache.putEachIntoCache(configuration, preprocessedInput, each);
    }
    return each;
}
Also used : IEngineConfiguration(org.thymeleaf.IEngineConfiguration) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException)

Example 38 with IEngineConfiguration

use of org.thymeleaf.IEngineConfiguration in project thymeleaf by thymeleaf.

the class OGNLVariableExpressionEvaluator method evaluate.

private static Object evaluate(final IExpressionContext context, final IStandardVariableExpression expression, final StandardExpressionExecutionContext expContext, final boolean applyOGNLShortcuts) {
    try {
        if (logger.isTraceEnabled()) {
            logger.trace("[THYMELEAF][{}] OGNL expression: evaluating expression \"{}\" on target", TemplateEngine.threadIndex(), expression.getExpression());
        }
        final IEngineConfiguration configuration = context.getConfiguration();
        final String exp = expression.getExpression();
        final boolean useSelectionAsRoot = expression.getUseSelectionAsRoot();
        if (exp == null) {
            throw new TemplateProcessingException("Expression content is null, which is not allowed");
        }
        final ComputedOGNLExpression parsedExpression = obtainComputedOGNLExpression(configuration, expression, exp, applyOGNLShortcuts);
        final Map<String, Object> contextVariablesMap;
        if (parsedExpression.mightNeedExpressionObjects) {
            // The IExpressionObjects implementation returned by processing contexts that include the Standard
            // Dialects will be lazy in the creation of expression objects (i.e. they won't be created until really
            // needed). And in order for this behaviour to be accepted by OGNL, we will be wrapping this object
            // inside an implementation of Map<String,Object>, which will afterwards be fed to the constructor
            // of an OgnlContext object.
            // Note this will never happen with shortcut expressions, as the '#' character with which all
            // expression object names start is not allowed by the OGNLShortcutExpression parser.
            final IExpressionObjects expressionObjects = context.getExpressionObjects();
            contextVariablesMap = new OGNLExpressionObjectsWrapper(expressionObjects, expContext.getRestrictVariableAccess());
            // can later lookup during evaluation.
            if (expContext.getRestrictVariableAccess()) {
                contextVariablesMap.put(OGNLContextPropertyAccessor.RESTRICT_REQUEST_PARAMETERS, OGNLContextPropertyAccessor.RESTRICT_REQUEST_PARAMETERS);
            } else {
                contextVariablesMap.remove(OGNLContextPropertyAccessor.RESTRICT_REQUEST_PARAMETERS);
            }
        } else {
            if (expContext.getRestrictVariableAccess()) {
                contextVariablesMap = CONTEXT_VARIABLES_MAP_NOEXPOBJECTS_RESTRICTIONS;
            } else {
                contextVariablesMap = Collections.EMPTY_MAP;
            }
        }
        // The root object on which we will evaluate expressions will depend on whether a selection target is
        // active or not...
        final ITemplateContext templateContext = (context instanceof ITemplateContext ? (ITemplateContext) context : null);
        final Object evaluationRoot = (useSelectionAsRoot && templateContext != null && templateContext.hasSelectionTarget() ? templateContext.getSelectionTarget() : templateContext);
        // Execute the expression!
        final Object result;
        try {
            result = executeExpression(configuration, parsedExpression.expression, contextVariablesMap, evaluationRoot);
        } catch (final OGNLShortcutExpression.OGNLShortcutExpressionNotApplicableException notApplicable) {
            // We tried to apply shortcuts, but it is not possible for this expression even if it parsed OK,
            // so we need to empty the cache and try again disabling shortcuts. Once processed for the first time,
            // an OGNL (non-shortcut) parsed expression will already be cached and this exception will not be
            // thrown again
            invalidateComputedOGNLExpression(configuration, expression, exp);
            return evaluate(context, expression, expContext, false);
        }
        if (!expContext.getPerformTypeConversion()) {
            return result;
        }
        final IStandardConversionService conversionService = StandardExpressions.getConversionService(configuration);
        return conversionService.convert(context, result, String.class);
    } catch (final Exception e) {
        throw new TemplateProcessingException("Exception evaluating OGNL expression: \"" + expression.getExpression() + "\"", e);
    }
}
Also used : IEngineConfiguration(org.thymeleaf.IEngineConfiguration) IExpressionObjects(org.thymeleaf.expression.IExpressionObjects) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) OgnlException(ognl.OgnlException) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) ITemplateContext(org.thymeleaf.context.ITemplateContext)

Example 39 with IEngineConfiguration

use of org.thymeleaf.IEngineConfiguration in project thymeleaf by thymeleaf.

the class AbstractStandardFragmentInsertionTagProcessor method doProcess.

@Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final AttributeName attributeName, final String attributeValue, final IElementTagStructureHandler structureHandler) {
    if (StringUtils.isEmptyOrWhitespace(attributeValue)) {
        throw new TemplateProcessingException("Fragment specifications cannot be empty");
    }
    final IEngineConfiguration configuration = context.getConfiguration();
    /*
         * PARSE AND PROCESS THE FRAGMENT
         */
    final Object fragmentObj = computeFragment(context, attributeValue);
    if (fragmentObj == null) {
        throw new TemplateInputException("Error resolving fragment: \"" + attributeValue + "\": " + "template or fragment could not be resolved");
    } else if (fragmentObj == NoOpToken.VALUE) {
        // If the Fragment result is NO-OP, we will just do nothing (apart from deleting the th:* attribute)
        return;
    } else if (fragmentObj == Fragment.EMPTY_FRAGMENT) {
        // tag (th:insert) or remove it completely, tag included (th:replace)
        if (this.replaceHost) {
            structureHandler.removeElement();
        } else {
            structureHandler.removeBody();
        }
        return;
    }
    final Fragment fragment = (Fragment) fragmentObj;
    final TemplateModel fragmentModel = fragment.getTemplateModel();
    Map<String, Object> fragmentParameters = fragment.getParameters();
    /*
         * ONCE WE HAVE THE FRAGMENT MODEL (its events, in fact), CHECK THE FRAGMENT SIGNATURE
         * Fragment signature is important because it might affect the way we apply the parameters to the fragment.
         *
         * Note this works whatever the template mode of the inserted fragment, given we are looking for an
         * element containing a "th:fragment/data-th-fragment" in a generic, non-template-dependent way.
         */
    // We will check types first instead of events in order to (many times) avoid creating an immutably-wrapped
    // event object when calling "model.get(pos)"
    boolean signatureApplied = false;
    final ITemplateEvent firstEvent = (fragmentModel.size() > 2 ? fragmentModel.get(1) : null);
    if (firstEvent != null && IProcessableElementTag.class.isAssignableFrom(firstEvent.getClass())) {
        final String dialectPrefix = attributeName.getPrefix();
        final IProcessableElementTag fragmentHolderEvent = (IProcessableElementTag) firstEvent;
        if (fragmentHolderEvent.hasAttribute(dialectPrefix, FRAGMENT_ATTR_NAME)) {
            // The selected fragment actually has a "th:fragment" attribute, so we should process its signature
            final String fragmentSignatureSpec = EscapedAttributeUtils.unescapeAttribute(fragmentModel.getTemplateMode(), fragmentHolderEvent.getAttributeValue(dialectPrefix, FRAGMENT_ATTR_NAME));
            if (!StringUtils.isEmptyOrWhitespace(fragmentSignatureSpec)) {
                final FragmentSignature fragmentSignature = FragmentSignatureUtils.parseFragmentSignature(configuration, fragmentSignatureSpec);
                if (fragmentSignature != null) {
                    // Reshape the fragment parameters into the ones that we will actually use, according to the signature
                    fragmentParameters = FragmentSignatureUtils.processParameters(fragmentSignature, fragmentParameters, fragment.hasSyntheticParameters());
                    signatureApplied = true;
                }
            }
        }
    }
    // not being applied, maybe not realising there was no signature assignation involved.
    if (!signatureApplied && fragment.hasSyntheticParameters()) {
        throw new TemplateProcessingException("Fragment '" + attributeValue + "' specifies synthetic (unnamed) parameters, but the resolved fragment " + "does not match a fragment signature (th:fragment,data-th-fragment) which could apply names to " + "the specified parameters.");
    }
    /*
         * CHECK WHETHER THIS IS A CROSS-TEMPLATE-MODE INSERTION. Only TemplateModels for the same template mode
         * can be safely inserted into the template being executed and processed just like any other sequences of
         * events. If the inserted template has a different template mode, we will need to process it aside and
         * obtain a String result for it, then insert such String as mere text.
         *
         * Note inserting large templates with a different template mode could therefore have a negative effect
         * on performance and memory usage, as their result needs to be completely stored in memory at some point
         * before being handled to the following phases of template processing. It is therefore recommended that
         * cross-template-mode fragment insertion is done only for small fragments, in which case it will work
         * almost the same as inlining (with the exception that the content to be inlined will be retrieved from
         * somewhere else by means of template resolution).
         */
    if (context.getTemplateMode() != fragmentModel.getTemplateMode()) {
        // Check if this is a th:include. If so, just don't allow
        if (this.insertOnlyContents) {
            throw new TemplateProcessingException("Template being processed uses template mode " + context.getTemplateMode() + ", " + "inserted fragment \"" + attributeValue + "\" uses template mode " + fragmentModel.getTemplateMode() + ". Cross-template-mode fragment insertion is not " + "allowed using the " + attributeName + " attribute, which is no longer recommended for use as " + "of Thymeleaf 3.0. Use {th:insert,data-th-insert} or {th:replace,data-th-replace} " + "instead, which do not remove the container element from the fragment being inserted.");
        }
        // doing it through the structure handler (we are going to perform a nested template processing operation)
        if (fragmentParameters != null && fragmentParameters.size() > 0) {
            if (!(context instanceof IEngineContext)) {
                throw new TemplateProcessingException("Parameterized fragment insertion is not supported because local variable support is DISABLED. This is due to " + "the use of an implementation of the " + ITemplateContext.class.getName() + " interface that does " + "not provide local-variable support. In order to have local-variable support, the variables map " + "implementation should also implement the " + IEngineContext.class.getName() + " interface");
            }
            // NOTE this IEngineContext interface is internal and should not be used in users' code
            ((IEngineContext) context).setVariables(fragmentParameters);
        }
        // Once parameters are in order, just process the template in a nested template engine execution
        final Writer stringWriter = new FastStringWriter(200);
        configuration.getTemplateManager().process(fragmentModel, context, stringWriter);
        // We will insert the result as NON-PROCESSABLE text (it's already been processed!)
        if (this.replaceHost) {
            structureHandler.replaceWith(stringWriter.toString(), false);
        } else {
            structureHandler.setBody(stringWriter.toString(), false);
        }
        return;
    }
    /*
         * APPLY THE FRAGMENT'S TEMPLATE RESOLUTION so that all code inside the fragment is executed with its own
         * template resolution info (working as if it were a local variable)
         */
    final TemplateData fragmentTemplateData = fragmentModel.getTemplateData();
    structureHandler.setTemplateData(fragmentTemplateData);
    /*
         * APPLY THE FRAGMENT PARAMETERS AS LOCAL VARIABLES, perhaps after reshaping it according to the fragment signature
         */
    if (fragmentParameters != null && fragmentParameters.size() > 0) {
        for (final Map.Entry<String, Object> fragmentParameterEntry : fragmentParameters.entrySet()) {
            structureHandler.setLocalVariable(fragmentParameterEntry.getKey(), fragmentParameterEntry.getValue());
        }
    }
    /*
         * IF WE ARE ASKING ONLY FOR CONTENTS (th:include), THEN REMOVE THE CONTAINER BLOCK
         */
    if (this.insertOnlyContents && fragmentTemplateData.hasTemplateSelectors()) {
        /*
             * In the case of th:include, things get a bit complicated because we need to remove the "element envelopes"
             * that contain what we really want to include (these envelopes' contents). So we will need to traverse
             * the entire returned model detecting those envelopes (open+close tags at model level == 0) and remove
             * them, along with anything else that is also at that level 0.
             */
        final IModel model = fragmentModel.cloneModel();
        int modelLevel = 0;
        int n = model.size();
        while (n-- != 0) {
            // We traverse backwards so that we can modify at the same time
            final ITemplateEvent event = model.get(n);
            if (event instanceof ICloseElementTag) {
                if (((ICloseElementTag) event).isUnmatched()) {
                    // This is an unmatched close tag (no corresponding open), therefore should not affect our count
                    continue;
                }
                if (modelLevel <= 0) {
                    model.remove(n);
                }
                modelLevel++;
                continue;
            }
            if (event instanceof IOpenElementTag) {
                modelLevel--;
                if (modelLevel <= 0) {
                    model.remove(n);
                }
                continue;
            }
            if (modelLevel <= 0) {
                model.remove(n);
            }
        }
        if (this.replaceHost) {
            structureHandler.replaceWith(model, true);
        } else {
            structureHandler.setBody(model, true);
        }
        return;
    }
    if (this.replaceHost) {
        structureHandler.replaceWith(fragmentModel, true);
    } else {
        structureHandler.setBody(fragmentModel, true);
    }
}
Also used : ITemplateEvent(org.thymeleaf.model.ITemplateEvent) IModel(org.thymeleaf.model.IModel) IEngineConfiguration(org.thymeleaf.IEngineConfiguration) IOpenElementTag(org.thymeleaf.model.IOpenElementTag) FragmentSignature(org.thymeleaf.standard.expression.FragmentSignature) TemplateModel(org.thymeleaf.engine.TemplateModel) Fragment(org.thymeleaf.standard.expression.Fragment) TemplateInputException(org.thymeleaf.exceptions.TemplateInputException) IEngineContext(org.thymeleaf.context.IEngineContext) TemplateData(org.thymeleaf.engine.TemplateData) IProcessableElementTag(org.thymeleaf.model.IProcessableElementTag) FastStringWriter(org.thymeleaf.util.FastStringWriter) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) ITemplateContext(org.thymeleaf.context.ITemplateContext) Map(java.util.Map) FastStringWriter(org.thymeleaf.util.FastStringWriter) Writer(java.io.Writer) ICloseElementTag(org.thymeleaf.model.ICloseElementTag)

Example 40 with IEngineConfiguration

use of org.thymeleaf.IEngineConfiguration in project thymeleaf by thymeleaf.

the class StandardUtextTagProcessor method doProcess.

@Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final AttributeName attributeName, final String attributeValue, final IElementTagStructureHandler structureHandler) {
    final IEngineConfiguration configuration = context.getConfiguration();
    final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
    final IStandardExpression expression = expressionParser.parseExpression(context, attributeValue);
    final Object expressionResult;
    if (expression != null && expression instanceof FragmentExpression) {
        // This is merely a FragmentExpression (not complex, not combined with anything), so we can apply a shortcut
        // so that we don't require a "null" result for this expression if the template does not exist. That will
        // save a call to resource.exists() which might be costly.
        final FragmentExpression.ExecutedFragmentExpression executedFragmentExpression = FragmentExpression.createExecutedFragmentExpression(context, (FragmentExpression) expression);
        expressionResult = FragmentExpression.resolveExecutedFragmentExpression(context, executedFragmentExpression, true);
    } else {
        expressionResult = expression.execute(context, StandardExpressionExecutionContext.RESTRICTED);
    }
    // If result is no-op, there's nothing to execute
    if (expressionResult == NoOpToken.VALUE) {
        return;
    }
    /*
         * First of all we should check whether the expression result is a Fragment so that, in such case, we can
         * avoid creating a String in memory for it and just append its model.
         */
    if (expressionResult != null && expressionResult instanceof Fragment) {
        if (expressionResult == Fragment.EMPTY_FRAGMENT) {
            structureHandler.removeBody();
            return;
        }
        structureHandler.setBody(((Fragment) expressionResult).getTemplateModel(), false);
        return;
    }
    final String unescapedTextStr = (expressionResult == null ? "" : expressionResult.toString());
    /*
         * We will check if there are configured post processors or not. The reason we do this is because output
         * inserted as a result of a th:utext attribute, even if it might be markup, will never be considered as
         * 'processable', i.e. no other processors/inliner will ever be able to act on it. The main reason for this
         * is to protect against code injection.
         *
         * So the only other agents that would be able to modify these th:utext results are POST-PROCESSORS. And
         * they will indeed need markup to have been parsed in order to separate text from structures, so that's why
         * we check if there actually are any post-processors and, if not (most common case), simply output the
         * expression result as if it were a mere (unescaped) text node.
         */
    final Set<IPostProcessor> postProcessors = configuration.getPostProcessors(getTemplateMode());
    if (postProcessors.isEmpty()) {
        structureHandler.setBody(unescapedTextStr, false);
        return;
    }
    /*
         * We have post-processors, so from here one we will have to decide whether we need to parse the unescaped
         * text or not...
         */
    if (!mightContainStructures(unescapedTextStr)) {
        // If this text contains no markup structures, there would be no need to parse it or treat it as markup!
        structureHandler.setBody(unescapedTextStr, false);
        return;
    }
    /*
         * We have post-processors AND this text might contain structures, so there is no alternative but parsing
         */
    final TemplateModel parsedFragment = configuration.getTemplateManager().parseString(context.getTemplateData(), unescapedTextStr, // we won't apply offset here because the inserted text does not really come from the template itself
    0, // we won't apply offset here because the inserted text does not really come from the template itself
    0, // No template mode forcing required
    null, // useCache == false because we could potentially pollute the cache with too many entries (th:utext is too variable!)
    false);
    // Setting 'processable' to false avoiding text inliners processing already generated text,
    // which in turn avoids code injection.
    structureHandler.setBody(parsedFragment, false);
}
Also used : IStandardExpression(org.thymeleaf.standard.expression.IStandardExpression) FragmentExpression(org.thymeleaf.standard.expression.FragmentExpression) IEngineConfiguration(org.thymeleaf.IEngineConfiguration) IPostProcessor(org.thymeleaf.postprocessor.IPostProcessor) IStandardExpressionParser(org.thymeleaf.standard.expression.IStandardExpressionParser) TemplateModel(org.thymeleaf.engine.TemplateModel) Fragment(org.thymeleaf.standard.expression.Fragment)

Aggregations

IEngineConfiguration (org.thymeleaf.IEngineConfiguration)45 Test (org.junit.Test)26 LinkedHashMap (java.util.LinkedHashMap)15 ServletContext (javax.servlet.ServletContext)14 HttpServletRequest (javax.servlet.http.HttpServletRequest)14 HttpServletResponse (javax.servlet.http.HttpServletResponse)14 WebEngineContext (org.thymeleaf.context.WebEngineContext)14 EngineContext (org.thymeleaf.context.EngineContext)10 TemplateProcessingException (org.thymeleaf.exceptions.TemplateProcessingException)8 TemplateInputException (org.thymeleaf.exceptions.TemplateInputException)6 IOException (java.io.IOException)3 ArrayList (java.util.ArrayList)3 EngineConfiguration (org.thymeleaf.EngineConfiguration)3 TemplateModel (org.thymeleaf.engine.TemplateModel)3 IPostProcessor (org.thymeleaf.postprocessor.IPostProcessor)3 File (java.io.File)2 FileInputStream (java.io.FileInputStream)2 InputStreamReader (java.io.InputStreamReader)2 Reader (java.io.Reader)2 StringReader (java.io.StringReader)2