From 3cdb866bda078a24d3fccb36b08a449a970a524f Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Fri, 4 Jan 2013 15:47:28 +0100 Subject: [PATCH] Relax ConfigurableWebEnvironment signatures ConfigurableWebEnvironment was introduced in 3.2.0.M1 with SPR-9439 in order to break a cyclic dependency. At the same time, certain signatures such as AbstractRefreshableWebApplicationContext#getEnviroment and GenericWebApplicationContext#getEnvironment were updated to take advantage of covariant return types and return this newer, more narrow type and providing cast-free calls to ConfigurableWebEnvironment methods where necessary. Similar changes were made to HttpServletBean in 3.2.0.M2 with SPR-9763. Narrowing #getEnvironment signatures in this fashion required enforcing at the #setEnvironment level that any Environment instance provided (explicitly or via the EnvironmentAware callback) must be an instance of ConfigurableWebEnvironment. This is a reasonable assertion in typical web application scenarios, but as SPR-10138 demonstrates, there are valid use cases in which one may want or need to inject a non-web ConfigurableEnvironment variant, e.g. during automated unit/integration testing. On review, it was never strictly necessary to narrow #getEnvironment signatures, although doing so did provided convenience and type safety. In order to maintain as flexible and backward-compatible an arrangement as possible, this commit relaxes these #getEnvironment signatures back to their original, pre-3.2 state. Namely, they now return ConfigurableEnvironment as opposed to ConfigurableWebEnvironment, and in accordance, all instanceof assertions have been removed or relaxed to ensure that injected Environment instances are of type ConfigurableEnvironment. These changes have been verified against David Winterfeldt's Spring by Example spring-rest-services project, as described at SPR-10138. Issue: SPR-10138, SPR-9763, SPR-9439 --- .../ConfigurableWebApplicationContext.java | 7 +------ .../web/context/ContextLoader.java | 6 +++++- ...tractRefreshableWebApplicationContext.java | 18 ++++++------------ .../support/GenericWebApplicationContext.java | 17 ++++++----------- .../support/StaticWebApplicationContext.java | 13 +------------ .../web/servlet/FrameworkServlet.java | 9 +++++++-- .../web/servlet/HttpServletBean.java | 19 +++++++++---------- .../web/servlet/DispatcherServletTests.java | 2 +- 8 files changed, 36 insertions(+), 55 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/context/ConfigurableWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/ConfigurableWebApplicationContext.java index a6185a81e8..cba5e1dbc3 100644 --- a/spring-web/src/main/java/org/springframework/web/context/ConfigurableWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/ConfigurableWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -71,11 +71,6 @@ public interface ConfigurableWebApplicationContext extends WebApplicationContext */ ServletConfig getServletConfig(); - /** - * Return the {@link ConfigurableWebEnvironment} used by this web application context. - */ - ConfigurableWebEnvironment getEnvironment(); - /** * Set the namespace for this web application context, * to be used for building a default context config location. diff --git a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java index 9880e9875e..69d812da37 100644 --- a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java +++ b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java @@ -38,6 +38,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.access.ContextSingletonBeanFactoryLocator; import org.springframework.core.GenericTypeResolver; import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.util.Assert; @@ -490,7 +491,10 @@ public class ContextLoader { initializerInstances.add(BeanUtils.instantiateClass(initializerClass)); } - applicationContext.getEnvironment().initPropertySources(servletContext, null); + ConfigurableEnvironment env = applicationContext.getEnvironment(); + if (env instanceof ConfigurableWebEnvironment) { + ((ConfigurableWebEnvironment)env).initPropertySources(servletContext, null); + } Collections.sort(initializerInstances, new AnnotationAwareOrderComparator()); for (ApplicationContextInitializer initializer : initializerInstances) { diff --git a/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java index f36bddc316..92b1f7907a 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -27,7 +27,6 @@ import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.ui.context.Theme; import org.springframework.ui.context.ThemeSource; import org.springframework.ui.context.support.UiApplicationContextUtils; -import org.springframework.util.Assert; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.ConfigurableWebEnvironment; import org.springframework.web.context.ServletConfigAware; @@ -157,15 +156,6 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR return new StandardServletEnvironment(); } - @Override - public ConfigurableWebEnvironment getEnvironment() { - ConfigurableEnvironment env = super.getEnvironment(); - Assert.isInstanceOf(ConfigurableWebEnvironment.class, env, - "ConfigurableWebApplicationContext environment must be of type " + - "ConfigurableWebEnvironment"); - return (ConfigurableWebEnvironment) env; - } - /** * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc. */ @@ -212,7 +202,11 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR @Override protected void initPropertySources() { super.initPropertySources(); - this.getEnvironment().initPropertySources(this.servletContext, this.servletConfig); + ConfigurableEnvironment env = this.getEnvironment(); + if (env instanceof ConfigurableWebEnvironment) { + ((ConfigurableWebEnvironment)env).initPropertySources( + this.servletContext, this.servletConfig); + } } public Theme getTheme(String themeName) { diff --git a/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java index ac87960cd0..d30d3aef84 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -147,15 +147,6 @@ public class GenericWebApplicationContext extends GenericApplicationContext return new StandardServletEnvironment(); } - @Override - public ConfigurableWebEnvironment getEnvironment() { - ConfigurableEnvironment env = super.getEnvironment(); - Assert.isInstanceOf(ConfigurableWebEnvironment.class, env, - "ConfigurableWebApplicationContext environment must be of type " + - "ConfigurableWebEnvironment"); - return (ConfigurableWebEnvironment) env; - } - /** * Register ServletContextAwareProcessor. * @see ServletContextAwareProcessor @@ -202,7 +193,11 @@ public class GenericWebApplicationContext extends GenericApplicationContext @Override protected void initPropertySources() { super.initPropertySources(); - this.getEnvironment().initPropertySources(this.servletContext, null); + ConfigurableEnvironment env = this.getEnvironment(); + if (env instanceof ConfigurableWebEnvironment) { + ((ConfigurableWebEnvironment)env).initPropertySources( + this.servletContext, null); + } } public Theme getTheme(String themeName) { diff --git a/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java index 5de71bda60..5d26a434e3 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -27,9 +27,7 @@ import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.ui.context.Theme; import org.springframework.ui.context.ThemeSource; import org.springframework.ui.context.support.UiApplicationContextUtils; -import org.springframework.util.Assert; import org.springframework.web.context.ConfigurableWebApplicationContext; -import org.springframework.web.context.ConfigurableWebEnvironment; import org.springframework.web.context.ServletConfigAware; import org.springframework.web.context.ServletContextAware; @@ -169,15 +167,6 @@ public class StaticWebApplicationContext extends StaticApplicationContext return new StandardServletEnvironment(); } - @Override - public ConfigurableWebEnvironment getEnvironment() { - ConfigurableEnvironment env = super.getEnvironment(); - Assert.isInstanceOf(ConfigurableWebEnvironment.class, env, - "ConfigurableWebApplication environment must be of type " + - "ConfigurableWebEnvironment"); - return (ConfigurableWebEnvironment) env; - } - /** * Initialize the theme capability. */ diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java index ca2a919043..3dca4eda94 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -39,11 +39,13 @@ import org.springframework.context.i18n.LocaleContext; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.SimpleLocaleContext; import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.ConfigurableWebEnvironment; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; @@ -638,7 +640,10 @@ public abstract class FrameworkServlet extends HttpServletBean { // the context is refreshed; do it eagerly here to ensure servlet property sources // are in place for use in any post-processing or initialization that occurs // below prior to #refresh - wac.getEnvironment().initPropertySources(getServletContext(), getServletConfig()); + ConfigurableEnvironment env = wac.getEnvironment(); + if (env instanceof ConfigurableWebEnvironment) { + ((ConfigurableWebEnvironment)env).initPropertySources(getServletContext(), getServletConfig()); + } postProcessWebApplicationContext(wac); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java index 044b56d2ae..bcd3a4d160 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -27,7 +27,6 @@ import javax.servlet.http.HttpServlet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; @@ -35,6 +34,7 @@ import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.Resource; @@ -42,9 +42,8 @@ import org.springframework.core.io.ResourceEditor; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import org.springframework.web.context.ConfigurableWebEnvironment; -import org.springframework.web.context.support.StandardServletEnvironment; import org.springframework.web.context.support.ServletContextResourceLoader; +import org.springframework.web.context.support.StandardServletEnvironment; /** * Simple extension of {@link javax.servlet.http.HttpServlet} which treats @@ -91,7 +90,7 @@ public abstract class HttpServletBean extends HttpServlet */ private final Set requiredProperties = new HashSet(); - private ConfigurableWebEnvironment environment; + private ConfigurableEnvironment environment; /** @@ -187,11 +186,11 @@ public abstract class HttpServletBean extends HttpServlet /** * {@inheritDoc} * @throws IllegalArgumentException if environment is not assignable to - * {@code ConfigurableWebEnvironment}. + * {@code ConfigurableEnvironment}. */ public void setEnvironment(Environment environment) { - Assert.isInstanceOf(ConfigurableWebEnvironment.class, environment); - this.environment = (ConfigurableWebEnvironment)environment; + Assert.isInstanceOf(ConfigurableEnvironment.class, environment); + this.environment = (ConfigurableEnvironment) environment; } /** @@ -199,7 +198,7 @@ public abstract class HttpServletBean extends HttpServlet *

If {@code null}, a new environment will be initialized via * {@link #createEnvironment()}. */ - public ConfigurableWebEnvironment getEnvironment() { + public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = this.createEnvironment(); } @@ -210,7 +209,7 @@ public abstract class HttpServletBean extends HttpServlet * Create and return a new {@link StandardServletEnvironment}. Subclasses may override * in order to configure the environment or specialize the environment type returned. */ - protected ConfigurableWebEnvironment createEnvironment() { + protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java index bb2d0a089b..b73e69ae6f 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java @@ -833,7 +833,7 @@ public class DispatcherServletTests extends TestCase { public void testEnvironmentOperations() { DispatcherServlet servlet = new DispatcherServlet(); - ConfigurableWebEnvironment defaultEnv = servlet.getEnvironment(); + ConfigurableEnvironment defaultEnv = servlet.getEnvironment(); assertThat(defaultEnv, notNullValue()); ConfigurableEnvironment env1 = new StandardServletEnvironment(); servlet.setEnvironment(env1); // should succeed