diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java index cf54d3d677..715a994965 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java @@ -18,10 +18,13 @@ package org.springframework.web.servlet.view; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.StringTokenizer; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -30,6 +33,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.BeanNameAware; import org.springframework.http.MediaType; import org.springframework.util.CollectionUtils; +import org.springframework.web.context.support.ContextExposingHttpServletRequest; import org.springframework.web.context.support.WebApplicationObjectSupport; import org.springframework.web.servlet.View; import org.springframework.web.servlet.support.RequestContext; @@ -68,12 +72,14 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement private String requestContextAttribute; - /** Map of static attributes, keyed by attribute name (String) */ private final Map staticAttributes = new LinkedHashMap(); - /** Whether or not the view should add path variables in the model */ private boolean exposePathVariables = true; + private boolean exposeContextBeansAsAttributes = false; + + private Set exposedContextBeanNames; + /** * Set the view's name. Helpful for traceability. @@ -248,6 +254,36 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement return this.exposePathVariables; } + /** + * Set whether to make all Spring beans in the application context accessible + * as request attributes, through lazy checking once an attribute gets accessed. + *

This will make all such beans accessible in plain {@code ${...}} + * expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out} + * value expressions. + *

Default is "false". Switch this flag on to transparently expose all + * Spring beans in the request attribute namespace. + *

NOTE: Context beans will override any custom request or session + * attributes of the same name that have been manually added. However, model + * attributes (as explicitly exposed to this view) of the same name will + * always override context beans. + * @see #getRequestToExpose + */ + public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) { + this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes; + } + + /** + * Specify the names of beans in the context which are supposed to be exposed. + * If this is non-null, only the specified beans are eligible for exposure as + * attributes. + *

If you'd like to expose all Spring beans in the application context, switch + * the {@link #setExposeContextBeansAsAttributes "exposeContextBeansAsAttributes"} + * flag on but do not list specific bean names for this property. + */ + public void setExposedContextBeanNames(String... exposedContextBeanNames) { + this.exposedContextBeanNames = new HashSet(Arrays.asList(exposedContextBeanNames)); + } + /** * Prepares the view given the specified model, merging it with static @@ -264,7 +300,7 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement Map mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); - renderMergedOutputModel(mergedModel, request, response); + renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); } /** @@ -276,12 +312,13 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement @SuppressWarnings("unchecked") Map pathVars = (this.exposePathVariables ? - (Map) request.getAttribute(View.PATH_VARIABLES) : null); + (Map) request.getAttribute(View.PATH_VARIABLES) : null); // Consolidate static and dynamic model attributes. int size = this.staticAttributes.size(); - size += (model != null) ? model.size() : 0; - size += (pathVars != null) ? pathVars.size() : 0; + size += (model != null ? model.size() : 0); + size += (pathVars != null ? pathVars.size() : 0); + Map mergedModel = new LinkedHashMap(size); mergedModel.putAll(this.staticAttributes); if (pathVars != null) { @@ -344,6 +381,24 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement return false; } + /** + * Get the request handle to expose to {@link #renderMergedOutputModel}, i.e. to the view. + *

The default implementation wraps the original request for exposure of Spring beans + * as request attributes (if demanded). + * @param originalRequest the original servlet request as provided by the engine + * @return the wrapped request, or the original request if no wrapping is necessary + * @see #setExposeContextBeansAsAttributes + * @see #setExposedContextBeanNames + * @see org.springframework.web.context.support.ContextExposingHttpServletRequest + */ + protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) { + if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) { + return new ContextExposingHttpServletRequest( + originalRequest, getWebApplicationContext(), this.exposedContextBeanNames); + } + return originalRequest; + } + /** * Subclasses must implement this method to actually render the view. *

The first step will be preparing the request: In the JSP case, diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceView.java index 7139a74ea4..8863a905f9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceView.java @@ -68,10 +68,6 @@ public class InternalResourceView extends AbstractUrlBasedView { private boolean alwaysInclude = false; - private boolean exposeContextBeansAsAttributes = false; - - private Set exposedContextBeanNames; - private boolean preventDispatchLoop = false; @@ -115,36 +111,6 @@ public class InternalResourceView extends AbstractUrlBasedView { this.alwaysInclude = alwaysInclude; } - /** - * Set whether to make all Spring beans in the application context accessible - * as request attributes, through lazy checking once an attribute gets accessed. - *

This will make all such beans accessible in plain {@code ${...}} - * expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out} - * value expressions. - *

Default is "false". Switch this flag on to transparently expose all - * Spring beans in the request attribute namespace. - *

NOTE: Context beans will override any custom request or session - * attributes of the same name that have been manually added. However, model - * attributes (as explicitly exposed to this view) of the same name will - * always override context beans. - * @see #getRequestToExpose - */ - public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) { - this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes; - } - - /** - * Specify the names of beans in the context which are supposed to be exposed. - * If this is non-null, only the specified beans are eligible for exposure as - * attributes. - *

If you'd like to expose all Spring beans in the application context, switch - * the {@link #setExposeContextBeansAsAttributes "exposeContextBeansAsAttributes"} - * flag on but do not list specific bean names for this property. - */ - public void setExposedContextBeanNames(String... exposedContextBeanNames) { - this.exposedContextBeanNames = new HashSet(Arrays.asList(exposedContextBeanNames)); - } - /** * Set whether to explicitly prevent dispatching back to the * current handler path. @@ -173,32 +139,29 @@ public class InternalResourceView extends AbstractUrlBasedView { protected void renderMergedOutputModel( Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { - // Determine which request handle to expose to the RequestDispatcher. - HttpServletRequest requestToExpose = getRequestToExpose(request); - // Expose the model object as request attributes. - exposeModelAsRequestAttributes(model, requestToExpose); + exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any. - exposeHelpers(requestToExpose); + exposeHelpers(request); // Determine the path for the request dispatcher. - String dispatcherPath = prepareForRendering(requestToExpose, response); + String dispatcherPath = prepareForRendering(request, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). - RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath); + RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } // If already included or response already committed, perform include, else forward. - if (useInclude(requestToExpose, response)) { + if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } - rd.include(requestToExpose, response); + rd.include(request, response); } else { @@ -206,27 +169,10 @@ public class InternalResourceView extends AbstractUrlBasedView { if (logger.isDebugEnabled()) { logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } - rd.forward(requestToExpose, response); + rd.forward(request, response); } } - /** - * Get the request handle to expose to the RequestDispatcher, i.e. to the view. - *

The default implementation wraps the original request for exposure of - * Spring beans as request attributes (if demanded). - * @param originalRequest the original servlet request as provided by the engine - * @return the wrapped request, or the original request if no wrapping is necessary - * @see #setExposeContextBeansAsAttributes - * @see org.springframework.web.context.support.ContextExposingHttpServletRequest - */ - protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) { - if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) { - return new ContextExposingHttpServletRequest( - originalRequest, getWebApplicationContext(), this.exposedContextBeanNames); - } - return originalRequest; - } - /** * Expose helpers unique to each rendering operation. This is necessary so that * different rendering operations can't overwrite each other's contexts etc. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java index e1866649a7..eb9a1bf5fc 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java @@ -52,10 +52,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { private Boolean alwaysInclude; - private Boolean exposeContextBeansAsAttributes; - - private String[] exposedContextBeanNames; - /** * Sets the default {@link #setViewClass view class} to {@link #requiredViewClass}: @@ -89,29 +85,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { this.alwaysInclude = alwaysInclude; } - /** - * Set whether to make all Spring beans in the application context accessible - * as request attributes, through lazy checking once an attribute gets accessed. - *

This will make all such beans accessible in plain {@code ${...}} - * expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out} - * value expressions. - *

Default is "false". - * @see InternalResourceView#setExposeContextBeansAsAttributes - */ - public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) { - this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes; - } - - /** - * Specify the names of beans in the context which are supposed to be exposed. - * If this is non-null, only the specified beans are eligible for exposure as - * attributes. - * @see InternalResourceView#setExposedContextBeanNames - */ - public void setExposedContextBeanNames(String... exposedContextBeanNames) { - this.exposedContextBeanNames = exposedContextBeanNames; - } - @Override protected AbstractUrlBasedView buildView(String viewName) throws Exception { @@ -119,12 +92,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { if (this.alwaysInclude != null) { view.setAlwaysInclude(this.alwaysInclude); } - if (this.exposeContextBeansAsAttributes != null) { - view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes); - } - if (this.exposedContextBeanNames != null) { - view.setExposedContextBeanNames(this.exposedContextBeanNames); - } view.setPreventDispatchLoop(true); return view; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java index fa2dda373d..8bd441eaed 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java @@ -119,6 +119,10 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements private Boolean exposePathVariables; + private Boolean exposeContextBeansAsAttributes; + + private String[] exposedContextBeanNames; + private String[] viewNames; private int order = Integer.MAX_VALUE; @@ -327,6 +331,37 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements return this.exposePathVariables; } + /** + * Set whether to make all Spring beans in the application context accessible + * as request attributes, through lazy checking once an attribute gets accessed. + *

This will make all such beans accessible in plain {@code ${...}} + * expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out} + * value expressions. + *

Default is "false". + * @see AbstractView#setExposeContextBeansAsAttributes + */ + public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) { + this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes; + } + + protected Boolean getExposeContextBeansAsAttributes() { + return this.exposeContextBeansAsAttributes; + } + + /** + * Specify the names of beans in the context which are supposed to be exposed. + * If this is non-null, only the specified beans are eligible for exposure as + * attributes. + * @see AbstractView#setExposedContextBeanNames + */ + public void setExposedContextBeanNames(String... exposedContextBeanNames) { + this.exposedContextBeanNames = exposedContextBeanNames; + } + + protected String[] getExposedContextBeanNames() { + return this.exposedContextBeanNames; + } + /** * Set the view names (or name patterns) that can be handled by this * {@link org.springframework.web.servlet.ViewResolver}. View names can contain @@ -482,6 +517,14 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements if (exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } + Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); + if (exposeContextBeansAsAttributes != null) { + view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); + } + String[] exposedContextBeanNames = getExposedContextBeanNames(); + if (exposedContextBeanNames != null) { + view.setExposedContextBeanNames(exposedContextBeanNames); + } return view; }