diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractTemplateView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractTemplateView.java index 3d028668df..aca0d81d82 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractTemplateView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractTemplateView.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,6 +66,8 @@ public abstract class AbstractTemplateView extends AbstractUrlBasedView { /** * Set whether all request attributes should be added to the * model prior to merging with the template. Default is "false". + *
Note that some templates may make request attributes visible + * on their own, e.g. FreeMarker, without exposure in the MVC model. */ public void setExposeRequestAttributes(boolean exposeRequestAttributes) { this.exposeRequestAttributes = exposeRequestAttributes; @@ -73,7 +75,7 @@ public abstract class AbstractTemplateView extends AbstractUrlBasedView { /** * Set whether HttpServletRequest attributes are allowed to override (hide) - * controller generated model attributes of the same name. Default is "false", + * controller generated model attributes of the same name. Default is "false" * which causes an exception to be thrown if request attributes of the same * name as model attributes are found. */ @@ -122,11 +124,11 @@ public abstract class AbstractTemplateView extends AbstractUrlBasedView { String attribute = en.nextElement(); if (model.containsKey(attribute) && !this.allowRequestOverride) { throw new ServletException("Cannot expose request attribute '" + attribute + - "' because of an existing model object of the same name"); + "' because of an existing model object of the same name"); } Object attributeValue = request.getAttribute(attribute); if (logger.isDebugEnabled()) { - exposed = exposed != null ? exposed : new LinkedHashMap<>(); + exposed = (exposed != null ? exposed : new LinkedHashMap<>()); exposed.put(attribute, attributeValue); } model.put(attribute, attributeValue); @@ -144,11 +146,11 @@ public abstract class AbstractTemplateView extends AbstractUrlBasedView { String attribute = en.nextElement(); if (model.containsKey(attribute) && !this.allowSessionOverride) { throw new ServletException("Cannot expose session attribute '" + attribute + - "' because of an existing model object of the same name"); + "' because of an existing model object of the same name"); } Object attributeValue = session.getAttribute(attribute); if (logger.isDebugEnabled()) { - exposed = exposed != null ? exposed : new LinkedHashMap<>(); + exposed = (exposed != null ? exposed : new LinkedHashMap<>()); exposed.put(attribute, attributeValue); } model.put(attribute, attributeValue); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java index 7d22d659ea..d82d0bebb7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,8 @@ import freemarker.template.ObjectWrapper; import freemarker.template.SimpleHash; import freemarker.template.Template; import freemarker.template.TemplateException; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -59,6 +61,9 @@ import org.springframework.web.servlet.view.AbstractTemplateView; * of this approach. * *
Note: Spring's FreeMarker support requires FreeMarker 2.3 or higher. + * As of Spring Framework 6.0, FreeMarker templates are rendered in a minimal + * fashion without JSP support, just exposing request attributes in addition + * to the MVC-provided model map for alignment with common Servlet resources. * * @author Darren Davison * @author Juergen Hoeller @@ -235,9 +240,6 @@ public class FreeMarkerView extends AbstractTemplateView { * bean property, retrieved via {@code getTemplate}. It delegates to the * {@code processTemplate} method to merge the template instance with * the given template model. - *
Adds the standard Freemarker hash models to the model: request parameters, - * request, session and application (ServletContext), as well as the JSP tag - * library hash model. *
Can be overridden to customize the behavior, for example to render * multiple templates into a single view. * @param model the model to use for rendering @@ -256,7 +258,7 @@ public class FreeMarkerView extends AbstractTemplateView { // Expose model to JSP tags (as request attributes). exposeModelAsRequestAttributes(model, request); - // Expose all standard FreeMarker hash models. + // Expose FreeMarker hash model. SimpleHash fmModel = buildTemplateModel(model, request, response); // Grab the locale-specific version of the template. @@ -266,7 +268,8 @@ public class FreeMarkerView extends AbstractTemplateView { /** * Build a FreeMarker template model for the given model Map. - *
The default implementation builds a {@link SimpleHash}. + *
The default implementation builds a {@link SimpleHash} for the
+ * given MVC model with an additional fallback to request attributes.
* @param model the model to use for rendering
* @param request current HTTP request
* @param response current servlet response
@@ -275,7 +278,7 @@ public class FreeMarkerView extends AbstractTemplateView {
protected SimpleHash buildTemplateModel(Map