All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.thymeleaf.spring5.dialect.SpringStandardDialect Maven / Gradle / Ivy

Go to download

Modern server-side Java template engine for both web and standalone environments

There is a newer version: 3.1.2.RELEASE
Show newest version
/*
 * =============================================================================
 *
 *   Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 * =============================================================================
 */
package org.thymeleaf.spring5.dialect;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import org.springframework.web.server.ServerWebExchange;
import org.thymeleaf.expression.IExpressionObjectFactory;
import org.thymeleaf.processor.IProcessor;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.context.SpringContextUtils;
import org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator;
import org.thymeleaf.spring5.expression.SpringStandardConversionService;
import org.thymeleaf.spring5.expression.SpringStandardExpressionObjectFactory;
import org.thymeleaf.spring5.expression.SpringStandardExpressions;
import org.thymeleaf.spring5.processor.SpringActionTagProcessor;
import org.thymeleaf.spring5.processor.SpringErrorClassTagProcessor;
import org.thymeleaf.spring5.processor.SpringErrorsTagProcessor;
import org.thymeleaf.spring5.processor.SpringHrefTagProcessor;
import org.thymeleaf.spring5.processor.SpringInputCheckboxFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringInputFileFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringInputPasswordFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringInputRadioFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringMethodTagProcessor;
import org.thymeleaf.spring5.processor.SpringObjectTagProcessor;
import org.thymeleaf.spring5.processor.SpringOptionFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringOptionInSelectFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringSelectFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringSrcTagProcessor;
import org.thymeleaf.spring5.processor.SpringTextareaFieldTagProcessor;
import org.thymeleaf.spring5.processor.SpringUErrorsTagProcessor;
import org.thymeleaf.spring5.processor.SpringValueTagProcessor;
import org.thymeleaf.spring5.util.SpringVersionUtils;
import org.thymeleaf.standard.StandardDialect;
import org.thymeleaf.standard.expression.IStandardConversionService;
import org.thymeleaf.standard.expression.IStandardVariableExpressionEvaluator;
import org.thymeleaf.standard.processor.StandardActionTagProcessor;
import org.thymeleaf.standard.processor.StandardHrefTagProcessor;
import org.thymeleaf.standard.processor.StandardMethodTagProcessor;
import org.thymeleaf.standard.processor.StandardObjectTagProcessor;
import org.thymeleaf.standard.processor.StandardSrcTagProcessor;
import org.thymeleaf.standard.processor.StandardValueTagProcessor;
import org.thymeleaf.templatemode.TemplateMode;

/**
 * 

* SpringStandard Dialect. This is the class containing the implementation of Thymeleaf Standard Dialect, including all * {@code th:*} processors, expression objects, etc. for Spring-enabled environments. *

*

* This dialect is valid both for Spring WebMVC and Spring WebFlux environments. *

*

* Note this dialect uses SpringEL as an expression language and adds some Spring-specific * features on top of {@link StandardDialect}, like {@code th:field} or Spring-related expression objects. *

*

* The usual and recommended way of using this dialect is by instancing {@link SpringTemplateEngine} * instead of {@link org.thymeleaf.TemplateEngine}. The former will automatically add this dialect and perform * some specific configuration like e.g. Spring-integrated message resolution. *

*

* Note a class with this name existed since 1.0, but it was completely reimplemented * in Thymeleaf 3.0 *

* * @author Daniel Fernández * * @since 3.0.3 * */ public class SpringStandardDialect extends StandardDialect { public static final String NAME = "SpringStandard"; public static final String PREFIX = "th"; public static final int PROCESSOR_PRECEDENCE = 1000; public static final boolean DEFAULT_ENABLE_SPRING_EL_COMPILER = false; public static final boolean DEFAULT_RENDER_HIDDEN_MARKERS_BEFORE_CHECKBOXES = false; private boolean enableSpringELCompiler = DEFAULT_ENABLE_SPRING_EL_COMPILER; private boolean renderHiddenMarkersBeforeCheckboxes = DEFAULT_RENDER_HIDDEN_MARKERS_BEFORE_CHECKBOXES; private static final Map REACTIVE_MODEL_ADDITIONS_EXECUTION_ATTRIBUTES; // This execution attribute will force the asynchronous resolution of the WebSession (not the real creation of a // persisted session) before view execution. This will avoid the need to block in order to obtain the WebSession // from the ServerWebExchange during template execution. // NOTE here we are not using the constant from the ReactiveThymeleafView class (instead we replicate its same // value "ThymeleafReactiveModelAdditions:" so that we don't force the initialisation of that class in // non-WebFlux environments. private static final String WEB_SESSION_EXECUTION_ATTRIBUTE_NAME = "ThymeleafReactiveModelAdditions:" + SpringContextUtils.WEB_SESSION_ATTRIBUTE_NAME; // These variables will be initialized lazily following the model applied in the extended StandardDialect. private IExpressionObjectFactory expressionObjectFactory = null; private IStandardConversionService conversionService = null; static { /* * If this is a WebFlux application, we will use a special mechanism in ThymeleafReactiveView that allows * the configuration of an execution attribute with a name with a certain prefix and type * Function>, so that such function is called during View preparation and * its result (Publisher) is put into the model so that Spring WebFlux asynchronously resolves it (without * blocking) before asking the View to actually render. * * This way, by means of this execution attribute we will set the Mono returned by * ServerWebExchange into the model and have Spring resolve it non-blockingly into the WebSession object we * could need during template execution. * * NOTE that, per the definition of WebSession in Spring WebFlux, even if this operation does mean the creation * of a WebSession instance, it does not mean the creation of a real (persisted) user session, cookie emission, * etc. unless anything is actually put afterwards into the session or it is explicitly started. */ if (!SpringVersionUtils.isSpringWebFluxPresent()) { REACTIVE_MODEL_ADDITIONS_EXECUTION_ATTRIBUTES = Collections.emptyMap(); } else { // Returns Mono, but we will specify Object in order not to bind this class to Mono at compile time final Function webSessionInitializer = (exchange) -> exchange.getSession(); REACTIVE_MODEL_ADDITIONS_EXECUTION_ATTRIBUTES = Collections.singletonMap(WEB_SESSION_EXECUTION_ATTRIBUTE_NAME, webSessionInitializer); } } public SpringStandardDialect() { super(NAME, PREFIX, PROCESSOR_PRECEDENCE); } /** *

* Returns whether the SpringEL compiler should be enabled in SpringEL expressions or not. *

*

* Expression compilation can significantly improve the performance of Spring EL expressions, but * might not be adequate for every environment. Read * the * official Spring documentation for more detail. *

*

* Also note that although Spring includes a SpEL compiler since Spring 4.1, most expressions * in Thymeleaf templates will only be able to properly benefit from this compilation step when at least * Spring Framework version 4.2.4 is used. *

*

* This flag is set to {@code false} by default. *

* * @return {@code true} if SpEL expressions should be compiled if possible, {@code false} if not. */ public boolean getEnableSpringELCompiler() { return enableSpringELCompiler; } /** *

* Sets whether the SpringEL compiler should be enabled in SpringEL expressions or not. *

*

* Expression compilation can significantly improve the performance of Spring EL expressions, but * might not be adequate for every environment. Read * the * official Spring documentation for more detail. *

*

* Also note that although Spring includes a SpEL compiler since Spring 4.1, most expressions * in Thymeleaf templates will only be able to properly benefit from this compilation step when at least * Spring Framework version 4.2.4 is used. *

*

* This flag is set to {@code false} by default. *

* * @param enableSpringELCompiler {@code true} if SpEL expressions should be compiled if possible, {@code false} if not. */ public void setEnableSpringELCompiler(final boolean enableSpringELCompiler) { this.enableSpringELCompiler = enableSpringELCompiler; } /** *

* Returns whether the {@code } marker tags rendered to signal the presence * of checkboxes in forms when unchecked should be rendered before the checkbox tag itself, * or after (default). *

*

* A number of CSS frameworks and style guides assume that the {@code

*

* Note this hidden field is introduced in order to signal the existence of the field in the form being sent, * even if the checkbox is unchecked (no URL parameter is added for unchecked check boxes). *

*

* This flag is set to {@code false} by default. *

* * @return {@code true} if hidden markers should be rendered before the checkboxes, {@code false} if not. * * @since 3.0.10 */ public boolean getRenderHiddenMarkersBeforeCheckboxes() { return renderHiddenMarkersBeforeCheckboxes; } /** *

* Sets whether the {@code } marker tags rendered to signal the presence * of checkboxes in forms when unchecked should be rendered before the checkbox tag itself, * or after (default). *

*

* A number of CSS frameworks and style guides assume that the {@code

*

* Note this hidden field is introduced in order to signal the existence of the field in the form being sent, * even if the checkbox is unchecked (no URL parameter is added for unchecked check boxes). *

*

* This flag is set to {@code false} by default. *

* * @param renderHiddenMarkersBeforeCheckboxes {@code true} if hidden markers should be rendered * before the checkboxes, {@code false} if not. * * @since 3.0.10 */ public void setRenderHiddenMarkersBeforeCheckboxes(final boolean renderHiddenMarkersBeforeCheckboxes) { this.renderHiddenMarkersBeforeCheckboxes = renderHiddenMarkersBeforeCheckboxes; } @Override public IStandardVariableExpressionEvaluator getVariableExpressionEvaluator() { return SPELVariableExpressionEvaluator.INSTANCE; } @Override public IStandardConversionService getConversionService() { if (this.conversionService == null) { this.conversionService = new SpringStandardConversionService(); } return this.conversionService; } @Override public IExpressionObjectFactory getExpressionObjectFactory() { if (this.expressionObjectFactory == null) { this.expressionObjectFactory = new SpringStandardExpressionObjectFactory(); } return this.expressionObjectFactory; } @Override public Set getProcessors(final String dialectPrefix) { return createSpringStandardProcessorsSet(dialectPrefix, this.renderHiddenMarkersBeforeCheckboxes); } @Override public Map getExecutionAttributes() { final Map executionAttributes = super.getExecutionAttributes(); executionAttributes.putAll(REACTIVE_MODEL_ADDITIONS_EXECUTION_ATTRIBUTES); executionAttributes.put( SpringStandardExpressions.ENABLE_SPRING_EL_COMPILER_ATTRIBUTE_NAME, Boolean.valueOf(getEnableSpringELCompiler())); return executionAttributes; } /** *

* Create a the set of SpringStandard processors, all of them freshly instanced. *

* * @param dialectPrefix the prefix established for the Standard Dialect, needed for initialization * @return the set of SpringStandard processors. */ public static Set createSpringStandardProcessorsSet(final String dialectPrefix) { return createSpringStandardProcessorsSet(dialectPrefix, DEFAULT_RENDER_HIDDEN_MARKERS_BEFORE_CHECKBOXES); } /** *

* Create a the set of SpringStandard processors, all of them freshly instanced. *

* * @param dialectPrefix the prefix established for the Standard Dialect, needed for initialization * @param renderHiddenMarkersBeforeCheckboxes {@code true} if hidden markers should be rendered * before the checkboxes, {@code false} if not. * * @return the set of SpringStandard processors. * * @since 3.0.10 */ public static Set createSpringStandardProcessorsSet( final String dialectPrefix, final boolean renderHiddenMarkersBeforeCheckboxes) { /* * It is important that we create new instances here because, if there are * several dialects in the TemplateEngine that extend StandardDialect, they should * not be returning the exact same instances for their processors in order * to allow specific instances to be directly linked with their owner dialect. */ final Set standardProcessors = StandardDialect.createStandardProcessorsSet(dialectPrefix); final Set processors = new LinkedHashSet(40); /* * REMOVE STANDARD PROCESSORS THAT WE WILL REPLACE */ for (final IProcessor standardProcessor : standardProcessors) { // There are several processors we need to remove from the Standard Dialect set if (!(standardProcessor instanceof StandardObjectTagProcessor) && !(standardProcessor instanceof StandardActionTagProcessor) && !(standardProcessor instanceof StandardHrefTagProcessor) && !(standardProcessor instanceof StandardMethodTagProcessor) && !(standardProcessor instanceof StandardSrcTagProcessor) && !(standardProcessor instanceof StandardValueTagProcessor)) { processors.add(standardProcessor); } else if (standardProcessor.getTemplateMode() != TemplateMode.HTML) { // We only want to remove from the StandardDialect the HTML versions of the attribute processors processors.add(standardProcessor); } } /* * ATTRIBUTE TAG PROCESSORS */ processors.add(new SpringActionTagProcessor(dialectPrefix)); processors.add(new SpringHrefTagProcessor(dialectPrefix)); processors.add(new SpringMethodTagProcessor(dialectPrefix)); processors.add(new SpringSrcTagProcessor(dialectPrefix)); processors.add(new SpringValueTagProcessor(dialectPrefix)); processors.add(new SpringObjectTagProcessor(dialectPrefix)); processors.add(new SpringErrorsTagProcessor(dialectPrefix)); processors.add(new SpringUErrorsTagProcessor(dialectPrefix)); processors.add(new SpringInputGeneralFieldTagProcessor(dialectPrefix)); processors.add(new SpringInputPasswordFieldTagProcessor(dialectPrefix)); processors.add(new SpringInputCheckboxFieldTagProcessor(dialectPrefix, renderHiddenMarkersBeforeCheckboxes)); processors.add(new SpringInputRadioFieldTagProcessor(dialectPrefix)); processors.add(new SpringInputFileFieldTagProcessor(dialectPrefix)); processors.add(new SpringSelectFieldTagProcessor(dialectPrefix)); processors.add(new SpringOptionInSelectFieldTagProcessor(dialectPrefix)); processors.add(new SpringOptionFieldTagProcessor(dialectPrefix)); processors.add(new SpringTextareaFieldTagProcessor(dialectPrefix)); processors.add(new SpringErrorClassTagProcessor(dialectPrefix)); return processors; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy