Merge pull request #160 from sbrannen/SPR-5243
Support loading WebApplicationContexts in the TCF
This commit is contained in:
commit
9937f840d5
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 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.
|
|
||||||
* 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.springframework.test.web.mock.servlet.samples.context;
|
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
|
||||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
|
||||||
import org.springframework.core.io.FileSystemResourceLoader;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.mock.web.MockRequestDispatcher;
|
|
||||||
import org.springframework.mock.web.MockServletContext;
|
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
|
||||||
import org.springframework.test.context.support.AbstractContextLoader;
|
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
|
||||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is here temporarily until the TestContext framework provides
|
|
||||||
* support for WebApplicationContext yet:
|
|
||||||
*
|
|
||||||
* https://jira.springsource.org/browse/SPR-5243
|
|
||||||
*
|
|
||||||
* <p>After that this class will no longer be needed. It's provided here as an example
|
|
||||||
* and to serve as a temporary solution.
|
|
||||||
*/
|
|
||||||
public class GenericWebContextLoader extends AbstractContextLoader {
|
|
||||||
protected final MockServletContext servletContext;
|
|
||||||
|
|
||||||
public GenericWebContextLoader(String warRootDir, boolean isClasspathRelative) {
|
|
||||||
ResourceLoader resourceLoader = isClasspathRelative ? new DefaultResourceLoader() : new FileSystemResourceLoader();
|
|
||||||
this.servletContext = initServletContext(warRootDir, resourceLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MockServletContext initServletContext(String warRootDir, ResourceLoader resourceLoader) {
|
|
||||||
return new MockServletContext(warRootDir, resourceLoader) {
|
|
||||||
// Required for DefaultServletHttpRequestHandler...
|
|
||||||
public RequestDispatcher getNamedDispatcher(String path) {
|
|
||||||
return (path.equals("default")) ? new MockRequestDispatcher(path) : super.getNamedDispatcher(path);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
|
||||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
|
||||||
context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
|
||||||
prepareContext(context);
|
|
||||||
loadBeanDefinitions(context, mergedConfig);
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationContext loadContext(String... locations) throws Exception {
|
|
||||||
// should never be called
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void prepareContext(GenericWebApplicationContext context) {
|
|
||||||
this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
|
|
||||||
context.setServletContext(this.servletContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void loadBeanDefinitions(GenericWebApplicationContext context, String[] locations) {
|
|
||||||
new XmlBeanDefinitionReader(context).loadBeanDefinitions(locations);
|
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
|
||||||
context.refresh();
|
|
||||||
context.registerShutdownHook();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void loadBeanDefinitions(GenericWebApplicationContext context, MergedContextConfiguration mergedConfig) {
|
|
||||||
new AnnotatedBeanDefinitionReader(context).register(mergedConfig.getClasses());
|
|
||||||
loadBeanDefinitions(context, mergedConfig.getLocations());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getResourceSuffix() {
|
|
||||||
return "-context.xml";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,9 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.test.web.mock.servlet.samples.context;
|
package org.springframework.test.web.mock.servlet.samples.context;
|
||||||
|
|
||||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
|
||||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
|
||||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -26,21 +25,20 @@ import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
import org.springframework.test.web.mock.servlet.MockMvc;
|
import org.springframework.test.web.mock.servlet.MockMvc;
|
||||||
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
|
||||||
import org.springframework.web.context.ContextLoader;
|
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests with Java configuration.
|
* Tests with Java configuration.
|
||||||
*
|
*
|
||||||
* The TestContext framework doesn't support WebApplicationContext yet:
|
* @author Rossen Stoyanchev
|
||||||
* https://jira.springsource.org/browse/SPR-5243
|
* @author Sam Brannen
|
||||||
*
|
|
||||||
* A custom {@link ContextLoader} is used to load the WebApplicationContext.
|
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration(loader=WebContextLoader.class, classes={WebConfig.class})
|
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||||
|
@ContextConfiguration(classes = WebConfig.class)
|
||||||
public class JavaTestContextTests {
|
public class JavaTestContextTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -48,6 +46,7 @@ public class JavaTestContextTests {
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||||
|
|
@ -55,8 +54,8 @@ public class JavaTestContextTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void tilesDefinitions() throws Exception {
|
public void tilesDefinitions() throws Exception {
|
||||||
this.mockMvc.perform(get("/"))
|
this.mockMvc.perform(get("/"))//
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())//
|
||||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
* 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.
|
* specific language governing permissions and limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.test.web.mock.servlet.samples.context;
|
package org.springframework.test.web.mock.servlet.samples.context;
|
||||||
|
|
||||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
|
@ -34,6 +35,7 @@ import org.springframework.security.web.FilterChainProxy;
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
import org.springframework.test.web.mock.servlet.MockMvc;
|
import org.springframework.test.web.mock.servlet.MockMvc;
|
||||||
import org.springframework.test.web.mock.servlet.MvcResult;
|
import org.springframework.test.web.mock.servlet.MvcResult;
|
||||||
import org.springframework.test.web.mock.servlet.ResultMatcher;
|
import org.springframework.test.web.mock.servlet.ResultMatcher;
|
||||||
|
|
@ -44,32 +46,25 @@ import org.springframework.web.context.WebApplicationContext;
|
||||||
/**
|
/**
|
||||||
* Basic example that includes Spring Security configuration.
|
* Basic example that includes Spring Security configuration.
|
||||||
*
|
*
|
||||||
* <p>Note that currently there are no {@link ResultMatcher}' built specifically
|
* <p>Note that currently there are no {@linkplain ResultMatcher ResultMatchers}
|
||||||
* for asserting the Spring Security context. However, it's quite easy to put
|
* built specifically for asserting the Spring Security context. However, it's
|
||||||
* them together as shown below and Spring Security extensions will become
|
* quite easy to put them together as shown below, and Spring Security extensions
|
||||||
* available in the near future.
|
* will become available in the near future.
|
||||||
*
|
*
|
||||||
* <p>This also demonstrates a custom {@link RequestPostProcessor} which authenticates
|
* <p>This also demonstrates a custom {@link RequestPostProcessor} which authenticates
|
||||||
* a user to a particular {@link HttpServletRequest}.
|
* a user to a particular {@link HttpServletRequest}.
|
||||||
*
|
*
|
||||||
* <p>Also see the Javadoc of {@link GenericWebContextLoader}, a class that
|
|
||||||
* provides temporary support for loading WebApplicationContext by extending
|
|
||||||
* the TestContext framework.
|
|
||||||
*
|
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Sam Brannen
|
||||||
* @see SecurityRequestPostProcessors
|
* @see SecurityRequestPostProcessors
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration(
|
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||||
loader=WebContextLoader.class,
|
@ContextConfiguration({ "security.xml", "../servlet-context.xml" })
|
||||||
value={
|
|
||||||
"classpath:org/springframework/test/web/mock/servlet/samples/context/security.xml",
|
|
||||||
"classpath:org/springframework/test/web/mock/servlet/samples/servlet-context.xml"
|
|
||||||
})
|
|
||||||
public class SpringSecurityTests {
|
public class SpringSecurityTests {
|
||||||
|
|
||||||
private static String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
|
private static final String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FilterChainProxy springSecurityFilterChain;
|
private FilterChainProxy springSecurityFilterChain;
|
||||||
|
|
@ -79,37 +74,44 @@ public class SpringSecurityTests {
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)//
|
||||||
.addFilters(this.springSecurityFilterChain).build();
|
.addFilters(this.springSecurityFilterChain)//
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void requiresAuthentication() throws Exception {
|
public void requiresAuthentication() throws Exception {
|
||||||
mockMvc.perform(get("/user"))
|
mockMvc.perform(get("/user")).//
|
||||||
.andExpect(redirectedUrl("http://localhost/spring_security_login"));
|
andExpect(redirectedUrl("http://localhost/spring_security_login"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessGranted() throws Exception {
|
public void accessGranted() throws Exception {
|
||||||
this.mockMvc.perform(get("/").with(userDeatilsService("user")))
|
this.mockMvc.perform(get("/").//
|
||||||
.andExpect(status().isOk())
|
with(userDeatilsService("user"))).//
|
||||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
andExpect(status().isOk()).//
|
||||||
|
andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessDenied() throws Exception {
|
public void accessDenied() throws Exception {
|
||||||
this.mockMvc.perform(get("/").with(user("user").roles("DENIED")))
|
this.mockMvc.perform(get("/")//
|
||||||
|
.with(user("user").roles("DENIED")))//
|
||||||
.andExpect(status().isForbidden());
|
.andExpect(status().isForbidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void userAuthenticates() throws Exception {
|
public void userAuthenticates() throws Exception {
|
||||||
final String username = "user";
|
final String username = "user";
|
||||||
mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "password"))
|
mockMvc.perform(post("/j_spring_security_check").//
|
||||||
.andExpect(redirectedUrl("/"))
|
param("j_username", username).//
|
||||||
.andExpect(new ResultMatcher() {
|
param("j_password", "password")).//
|
||||||
|
andExpect(redirectedUrl("/")).//
|
||||||
|
andExpect(new ResultMatcher() {
|
||||||
|
|
||||||
public void match(MvcResult mvcResult) throws Exception {
|
public void match(MvcResult mvcResult) throws Exception {
|
||||||
HttpSession session = mvcResult.getRequest().getSession();
|
HttpSession session = mvcResult.getRequest().getSession();
|
||||||
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
||||||
|
|
@ -121,9 +123,12 @@ public class SpringSecurityTests {
|
||||||
@Test
|
@Test
|
||||||
public void userAuthenticateFails() throws Exception {
|
public void userAuthenticateFails() throws Exception {
|
||||||
final String username = "user";
|
final String username = "user";
|
||||||
mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "invalid"))
|
mockMvc.perform(post("/j_spring_security_check").//
|
||||||
.andExpect(redirectedUrl("/spring_security_login?login_error"))
|
param("j_username", username).//
|
||||||
.andExpect(new ResultMatcher() {
|
param("j_password", "invalid")).//
|
||||||
|
andExpect(redirectedUrl("/spring_security_login?login_error")).//
|
||||||
|
andExpect(new ResultMatcher() {
|
||||||
|
|
||||||
public void match(MvcResult mvcResult) throws Exception {
|
public void match(MvcResult mvcResult) throws Exception {
|
||||||
HttpSession session = mvcResult.getRequest().getSession();
|
HttpSession session = mvcResult.getRequest().getSession();
|
||||||
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.test.web.mock.servlet.samples.context;
|
package org.springframework.test.web.mock.servlet.samples.context;
|
||||||
|
|
||||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
|
||||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
|
||||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -26,23 +25,20 @@ import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
import org.springframework.test.web.mock.servlet.MockMvc;
|
import org.springframework.test.web.mock.servlet.MockMvc;
|
||||||
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
|
||||||
import org.springframework.web.context.ContextLoader;
|
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests with XML configuration.
|
* Tests with XML configuration.
|
||||||
*
|
*
|
||||||
* The TestContext framework doesn't support WebApplicationContext yet:
|
* @author Rossen Stoyanchev
|
||||||
* https://jira.springsource.org/browse/SPR-5243
|
* @author Sam Brannen
|
||||||
*
|
|
||||||
* A custom {@link ContextLoader} is used to load the WebApplicationContext.
|
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration(
|
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||||
loader=WebContextLoader.class,
|
@ContextConfiguration("../servlet-context.xml")
|
||||||
locations={"/org/springframework/test/web/mock/servlet/samples/servlet-context.xml"})
|
|
||||||
public class XmlTestContextTests {
|
public class XmlTestContextTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -50,6 +46,7 @@ public class XmlTestContextTests {
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||||
|
|
@ -57,10 +54,9 @@ public class XmlTestContextTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void tilesDefinitions() throws Exception {
|
public void tilesDefinitions() throws Exception {
|
||||||
this.mockMvc.perform(get("/"))
|
this.mockMvc.perform(get("/"))//
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())//
|
||||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<configs>
|
<configs>
|
||||||
<config>src/test/java/org/springframework/test/context/junit4/profile/xml/DefaultProfileXmlConfigTests-context.xml</config>
|
<config>src/test/java/org/springframework/test/context/junit4/profile/xml/DefaultProfileXmlConfigTests-context.xml</config>
|
||||||
<config>src/test/java/org/springframework/test/context/junit4/aci/xml/MultipleInitializersXmlConfigTests-context.xml</config>
|
<config>src/test/java/org/springframework/test/context/junit4/aci/xml/MultipleInitializersXmlConfigTests-context.xml</config>
|
||||||
|
<config>src/test/resources/org/springframework/test/context/web/BasicXmlWacTests-config.xml</config>
|
||||||
</configs>
|
</configs>
|
||||||
<configSets>
|
<configSets>
|
||||||
</configSets>
|
</configSets>
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.test.context;
|
package org.springframework.test.context;
|
||||||
|
|
||||||
import static org.springframework.beans.BeanUtils.instantiateClass;
|
import static org.springframework.beans.BeanUtils.*;
|
||||||
import static org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClass;
|
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
@ -30,6 +30,8 @@ import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.context.ApplicationContextInitializer;
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
@ -54,6 +56,7 @@ abstract class ContextLoaderUtils {
|
||||||
private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class);
|
private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class);
|
||||||
|
|
||||||
private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.DelegatingSmartContextLoader";
|
private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.DelegatingSmartContextLoader";
|
||||||
|
private static final String DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.WebDelegatingSmartContextLoader";
|
||||||
|
|
||||||
|
|
||||||
private ContextLoaderUtils() {
|
private ContextLoaderUtils() {
|
||||||
|
|
@ -83,7 +86,8 @@ abstract class ContextLoaderUtils {
|
||||||
Assert.notNull(testClass, "Test class must not be null");
|
Assert.notNull(testClass, "Test class must not be null");
|
||||||
|
|
||||||
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
||||||
defaultContextLoaderClassName = DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
defaultContextLoaderClassName = testClass.isAnnotationPresent(WebAppConfiguration.class) ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
|
||||||
|
: DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
|
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
|
||||||
|
|
@ -394,6 +398,14 @@ abstract class ContextLoaderUtils {
|
||||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = resolveInitializerClasses(configAttributesList);
|
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = resolveInitializerClasses(configAttributesList);
|
||||||
String[] activeProfiles = resolveActiveProfiles(testClass);
|
String[] activeProfiles = resolveActiveProfiles(testClass);
|
||||||
|
|
||||||
|
if (testClass.isAnnotationPresent(WebAppConfiguration.class)) {
|
||||||
|
WebAppConfiguration webAppConfig = testClass.getAnnotation(WebAppConfiguration.class);
|
||||||
|
String resourceBasePath = webAppConfig.value();
|
||||||
|
return new WebMergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
|
||||||
|
resourceBasePath, contextLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// else
|
||||||
return new MergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
|
return new MergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
|
||||||
contextLoader);
|
contextLoader);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ public class MergedContextConfiguration implements Serializable {
|
||||||
* {@link ContextLoader} based solely on the fully qualified name of the
|
* {@link ContextLoader} based solely on the fully qualified name of the
|
||||||
* loader or "null" if the supplied loaded is <code>null</code>.
|
* loader or "null" if the supplied loaded is <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private static String nullSafeToString(ContextLoader contextLoader) {
|
protected static String nullSafeToString(ContextLoader contextLoader) {
|
||||||
return contextLoader == null ? "null" : contextLoader.getClass().getName();
|
return contextLoader == null ? "null" : contextLoader.getClass().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
*/
|
*/
|
||||||
private ApplicationContext loadApplicationContext() throws Exception {
|
private ApplicationContext loadApplicationContext() throws Exception {
|
||||||
ContextLoader contextLoader = mergedContextConfiguration.getContextLoader();
|
ContextLoader contextLoader = mergedContextConfiguration.getContextLoader();
|
||||||
Assert.notNull(contextLoader, "Can not load an ApplicationContext with a NULL 'contextLoader'. "
|
Assert.notNull(contextLoader, "Cannot load an ApplicationContext with a NULL 'contextLoader'. "
|
||||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||||
|
|
||||||
ApplicationContext applicationContext;
|
ApplicationContext applicationContext;
|
||||||
|
|
@ -125,7 +125,7 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String[] locations = mergedContextConfiguration.getLocations();
|
String[] locations = mergedContextConfiguration.getLocations();
|
||||||
Assert.notNull(locations, "Can not load an ApplicationContext with a NULL 'locations' array. "
|
Assert.notNull(locations, "Cannot load an ApplicationContext with a NULL 'locations' array. "
|
||||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||||
applicationContext = contextLoader.loadContext(locations);
|
applicationContext = contextLoader.loadContext(locations);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ import org.springframework.util.ObjectUtils;
|
||||||
public class TestContextManager {
|
public class TestContextManager {
|
||||||
|
|
||||||
private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
|
private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
|
||||||
|
"org.springframework.test.context.web.WebTestExecutionListener",
|
||||||
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
|
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
|
||||||
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
|
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
|
||||||
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
|
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
|
||||||
|
|
@ -126,7 +127,6 @@ public class TestContextManager {
|
||||||
return this.testContext;
|
return this.testContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the supplied {@link TestExecutionListener TestExecutionListeners}
|
* Register the supplied {@link TestExecutionListener TestExecutionListeners}
|
||||||
* by appending them to the set of listeners used by this <code>TestContextManager</code>.
|
* by appending them to the set of listeners used by this <code>TestContextManager</code>.
|
||||||
|
|
@ -155,8 +155,8 @@ public class TestContextManager {
|
||||||
* registered for this <code>TestContextManager</code> in reverse order.
|
* registered for this <code>TestContextManager</code> in reverse order.
|
||||||
*/
|
*/
|
||||||
private List<TestExecutionListener> getReversedTestExecutionListeners() {
|
private List<TestExecutionListener> getReversedTestExecutionListeners() {
|
||||||
List<TestExecutionListener> listenersReversed =
|
List<TestExecutionListener> listenersReversed = new ArrayList<TestExecutionListener>(
|
||||||
new ArrayList<TestExecutionListener>(getTestExecutionListeners());
|
getTestExecutionListeners());
|
||||||
Collections.reverse(listenersReversed);
|
Collections.reverse(listenersReversed);
|
||||||
return listenersReversed;
|
return listenersReversed;
|
||||||
}
|
}
|
||||||
|
|
@ -186,8 +186,7 @@ public class TestContextManager {
|
||||||
}
|
}
|
||||||
classesList.addAll(getDefaultTestExecutionListenerClasses());
|
classesList.addAll(getDefaultTestExecutionListenerClasses());
|
||||||
defaultListeners = true;
|
defaultListeners = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Traverse the class hierarchy...
|
// Traverse the class hierarchy...
|
||||||
while (declaringClass != null) {
|
while (declaringClass != null) {
|
||||||
TestExecutionListeners testExecutionListeners = declaringClass.getAnnotation(annotationType);
|
TestExecutionListeners testExecutionListeners = declaringClass.getAnnotation(annotationType);
|
||||||
|
|
@ -200,22 +199,21 @@ public class TestContextManager {
|
||||||
Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
|
Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
|
||||||
if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
|
if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] " +
|
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] "
|
||||||
"and 'listeners' [%s] attributes. Use one or the other, but not both.",
|
+ "and 'listeners' [%s] attributes. Use one or the other, but not both.",
|
||||||
declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
|
declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
|
||||||
ObjectUtils.nullSafeToString(listenerClasses));
|
ObjectUtils.nullSafeToString(listenerClasses));
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new IllegalStateException(msg);
|
throw new IllegalStateException(msg);
|
||||||
}
|
} else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
|
||||||
else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
|
|
||||||
listenerClasses = valueListenerClasses;
|
listenerClasses = valueListenerClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listenerClasses != null) {
|
if (listenerClasses != null) {
|
||||||
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
|
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
|
||||||
}
|
}
|
||||||
declaringClass = (testExecutionListeners.inheritListeners() ?
|
declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||||
AnnotationUtils.findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass()) : null);
|
annotationType, declaringClass.getSuperclass()) : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,16 +221,14 @@ public class TestContextManager {
|
||||||
for (Class<? extends TestExecutionListener> listenerClass : classesList) {
|
for (Class<? extends TestExecutionListener> listenerClass : classesList) {
|
||||||
try {
|
try {
|
||||||
listeners.add(BeanUtils.instantiateClass(listenerClass));
|
listeners.add(BeanUtils.instantiateClass(listenerClass));
|
||||||
}
|
} catch (NoClassDefFoundError err) {
|
||||||
catch (NoClassDefFoundError err) {
|
|
||||||
if (defaultListeners) {
|
if (defaultListeners) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Could not instantiate default TestExecutionListener class ["
|
logger.debug("Could not instantiate default TestExecutionListener class ["
|
||||||
+ listenerClass.getName()
|
+ listenerClass.getName()
|
||||||
+ "]. Specify custom listener classes or make the default listener classes available.");
|
+ "]. Specify custom listener classes or make the default listener classes available.");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -245,24 +241,21 @@ public class TestContextManager {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() {
|
protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() {
|
||||||
Set<Class<? extends TestExecutionListener>> defaultListenerClasses =
|
Set<Class<? extends TestExecutionListener>> defaultListenerClasses = new LinkedHashSet<Class<? extends TestExecutionListener>>();
|
||||||
new LinkedHashSet<Class<? extends TestExecutionListener>>();
|
|
||||||
for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) {
|
for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) {
|
||||||
try {
|
try {
|
||||||
defaultListenerClasses.add(
|
defaultListenerClasses.add((Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(
|
||||||
(Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(className));
|
className));
|
||||||
}
|
} catch (Throwable t) {
|
||||||
catch (Throwable ex) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Could not load default TestExecutionListener class [" + className
|
logger.debug("Could not load default TestExecutionListener class [" + className
|
||||||
+ "]. Specify custom listener classes or make the default listener classes available.");
|
+ "]. Specify custom listener classes or make the default listener classes available.", t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaultListenerClasses;
|
return defaultListenerClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for pre-processing a test class <em>before</em> execution of any
|
* Hook for pre-processing a test class <em>before</em> execution of any
|
||||||
* tests within the class. Should be called prior to any framework-specific
|
* tests within the class. Should be called prior to any framework-specific
|
||||||
|
|
@ -286,8 +279,7 @@ public class TestContextManager {
|
||||||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||||
try {
|
try {
|
||||||
testExecutionListener.beforeTestClass(getTestContext());
|
testExecutionListener.beforeTestClass(getTestContext());
|
||||||
}
|
} catch (Exception ex) {
|
||||||
catch (Exception ex) {
|
|
||||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||||
+ "] to process 'before class' callback for test class [" + testClass + "]", ex);
|
+ "] to process 'before class' callback for test class [" + testClass + "]", ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
|
|
@ -319,8 +311,7 @@ public class TestContextManager {
|
||||||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||||
try {
|
try {
|
||||||
testExecutionListener.prepareTestInstance(getTestContext());
|
testExecutionListener.prepareTestInstance(getTestContext());
|
||||||
}
|
} catch (Exception ex) {
|
||||||
catch (Exception ex) {
|
|
||||||
logger.error("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
logger.error("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||||
+ "] to prepare test instance [" + testInstance + "]", ex);
|
+ "] to prepare test instance [" + testInstance + "]", ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
|
|
@ -356,8 +347,7 @@ public class TestContextManager {
|
||||||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||||
try {
|
try {
|
||||||
testExecutionListener.beforeTestMethod(getTestContext());
|
testExecutionListener.beforeTestMethod(getTestContext());
|
||||||
}
|
} catch (Exception ex) {
|
||||||
catch (Exception ex) {
|
|
||||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||||
+ "] to process 'before' execution of test method [" + testMethod + "] for test instance ["
|
+ "] to process 'before' execution of test method [" + testMethod + "] for test instance ["
|
||||||
+ testInstance + "]", ex);
|
+ testInstance + "]", ex);
|
||||||
|
|
@ -404,8 +394,7 @@ public class TestContextManager {
|
||||||
for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
|
for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
|
||||||
try {
|
try {
|
||||||
testExecutionListener.afterTestMethod(getTestContext());
|
testExecutionListener.afterTestMethod(getTestContext());
|
||||||
}
|
} catch (Exception ex) {
|
||||||
catch (Exception ex) {
|
|
||||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||||
+ "] to process 'after' execution for test: method [" + testMethod + "], instance ["
|
+ "] to process 'after' execution for test: method [" + testMethod + "], instance ["
|
||||||
+ testInstance + "], exception [" + exception + "]", ex);
|
+ testInstance + "], exception [" + exception + "]", ex);
|
||||||
|
|
@ -446,8 +435,7 @@ public class TestContextManager {
|
||||||
for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
|
for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
|
||||||
try {
|
try {
|
||||||
testExecutionListener.afterTestClass(getTestContext());
|
testExecutionListener.afterTestClass(getTestContext());
|
||||||
}
|
} catch (Exception ex) {
|
||||||
catch (Exception ex) {
|
|
||||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||||
+ "] to process 'after class' callback for test class [" + testClass + "]", ex);
|
+ "] to process 'after class' callback for test class [" + testClass + "]", ex);
|
||||||
if (afterTestClassException == null) {
|
if (afterTestClassException == null) {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,24 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
package org.springframework.test.context.support;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.core.GenericTypeResolver;
|
||||||
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||||
import org.springframework.test.context.ContextLoader;
|
import org.springframework.test.context.ContextLoader;
|
||||||
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
import org.springframework.test.context.SmartContextLoader;
|
import org.springframework.test.context.SmartContextLoader;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
@ -81,6 +92,64 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||||
configAttributes.setLocations(processedLocations);
|
configAttributes.setLocations(processedLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the {@link ConfigurableApplicationContext} created by this
|
||||||
|
* {@code SmartContextLoader} <i>before</i> bean definitions are read.
|
||||||
|
*
|
||||||
|
* <p>The default implementation:
|
||||||
|
* <ul>
|
||||||
|
* <li>Sets the <em>active bean definition profiles</em> from the supplied
|
||||||
|
* <code>MergedContextConfiguration</code> in the
|
||||||
|
* {@link org.springframework.core.env.Environment Environment} of the context.</li>
|
||||||
|
* <li>Determines what (if any) context initializer classes have been supplied
|
||||||
|
* via the {@code MergedContextConfiguration} and
|
||||||
|
* {@linkplain ApplicationContextInitializer#initialize invokes each} with the
|
||||||
|
* given application context.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Any {@code ApplicationContextInitializers} implementing
|
||||||
|
* {@link org.springframework.core.Ordered Ordered} or marked with {@link
|
||||||
|
* org.springframework.core.annotation.Order @Order} will be sorted appropriately.
|
||||||
|
*
|
||||||
|
* @param context the newly created application context
|
||||||
|
* @param mergedConfig the merged context configuration
|
||||||
|
* @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
|
||||||
|
* @see #loadContext(MergedContextConfiguration)
|
||||||
|
* @see ConfigurableApplicationContext#setId
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||||
|
|
||||||
|
context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
||||||
|
|
||||||
|
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
|
||||||
|
|
||||||
|
if (initializerClasses.size() == 0) {
|
||||||
|
// no ApplicationContextInitializers have been declared -> nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
||||||
|
final Class<?> contextClass = context.getClass();
|
||||||
|
|
||||||
|
for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
|
||||||
|
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
|
||||||
|
ApplicationContextInitializer.class);
|
||||||
|
Assert.isAssignable(initializerContextClass, contextClass, String.format(
|
||||||
|
"Could not add context initializer [%s] since its generic parameter [%s] "
|
||||||
|
+ "is not assignable from the type of application context used by this "
|
||||||
|
+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
|
||||||
|
contextClass.getName()));
|
||||||
|
initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
|
||||||
|
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
|
||||||
|
initializer.initialize(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- ContextLoader -------------------------------------------------------
|
// --- ContextLoader -------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -185,12 +254,10 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||||
String path = locations[i];
|
String path = locations[i];
|
||||||
if (path.startsWith(SLASH)) {
|
if (path.startsWith(SLASH)) {
|
||||||
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
||||||
}
|
} else if (!ResourcePatternUtils.isUrl(path)) {
|
||||||
else if (!ResourcePatternUtils.isUrl(path)) {
|
|
||||||
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH
|
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH
|
||||||
+ StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
|
+ StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
modifiedLocations[i] = StringUtils.cleanPath(path);
|
modifiedLocations[i] = StringUtils.cleanPath(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,287 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.support;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||||
|
import org.springframework.test.context.ContextLoader;
|
||||||
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
|
import org.springframework.test.context.SmartContextLoader;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code AbstractDelegatingSmartContextLoader} serves as an abstract base class
|
||||||
|
* for implementations of the {@link SmartContextLoader} SPI that delegate to a
|
||||||
|
* set of <em>candidate</em> SmartContextLoaders (i.e., one that supports XML
|
||||||
|
* configuration files and one that supports annotated classes) to determine which
|
||||||
|
* context loader is appropriate for a given test class's configuration. Each
|
||||||
|
* candidate is given a chance to {@link #processContextConfiguration process} the
|
||||||
|
* {@link ContextConfigurationAttributes} for each class in the test class hierarchy
|
||||||
|
* that is annotated with {@link ContextConfiguration @ContextConfiguration}, and
|
||||||
|
* the candidate that supports the merged, processed configuration will be used to
|
||||||
|
* actually {@link #loadContext load} the context.
|
||||||
|
*
|
||||||
|
* <p>Placing an empty {@code @ContextConfiguration} annotation on a test class signals
|
||||||
|
* that default resource locations (i.e., XML configuration files) or default
|
||||||
|
* {@link org.springframework.context.annotation.Configuration configuration classes}
|
||||||
|
* should be detected. Furthermore, if a specific {@link ContextLoader} or
|
||||||
|
* {@link SmartContextLoader} is not explicitly declared via
|
||||||
|
* {@code @ContextConfiguration}, a concrete subclass of
|
||||||
|
* {@code AbstractDelegatingSmartContextLoader} will be used as the default loader,
|
||||||
|
* thus providing automatic support for either XML configuration files or annotated
|
||||||
|
* classes, but not both simultaneously.
|
||||||
|
*
|
||||||
|
* <p>As of Spring 3.2, a test class may optionally declare neither XML configuration
|
||||||
|
* files nor annotated classes and instead declare only {@linkplain
|
||||||
|
* ContextConfiguration#initializers application context initializers}. In such
|
||||||
|
* cases, an attempt will still be made to detect defaults, but their absence will
|
||||||
|
* not result an an exception.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
* @see SmartContextLoader
|
||||||
|
*/
|
||||||
|
abstract class AbstractDelegatingSmartContextLoader implements SmartContextLoader {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AbstractDelegatingSmartContextLoader.class);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the delegate {@code SmartContextLoader} that supports XML configuration files.
|
||||||
|
*/
|
||||||
|
protected abstract SmartContextLoader getXmlLoader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the delegate {@code SmartContextLoader} that supports annotated classes.
|
||||||
|
*/
|
||||||
|
protected abstract SmartContextLoader getAnnotationConfigLoader();
|
||||||
|
|
||||||
|
// --- SmartContextLoader --------------------------------------------------
|
||||||
|
|
||||||
|
private static String name(SmartContextLoader loader) {
|
||||||
|
return loader.getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader),
|
||||||
|
configAttributes));
|
||||||
|
}
|
||||||
|
loader.processContextConfiguration(configAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
|
||||||
|
throws Exception {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
||||||
|
}
|
||||||
|
return loader.loadContext(mergedConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
||||||
|
if (loader == getAnnotationConfigLoader()) {
|
||||||
|
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||||
|
} else {
|
||||||
|
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
|
||||||
|
* {@link ContextConfigurationAttributes}.
|
||||||
|
*
|
||||||
|
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||||
|
* default loaders for {@link #getXmlLoader() XML configuration files} and
|
||||||
|
* {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
|
||||||
|
* delegation algorithm is as follows:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>If the resource locations or annotated classes in the supplied
|
||||||
|
* {@code ContextConfigurationAttributes} are not empty, the appropriate
|
||||||
|
* candidate loader will be allowed to process the configuration <em>as is</em>,
|
||||||
|
* without any checks for detection of defaults.</li>
|
||||||
|
* <li>Otherwise, the XML-based loader will be allowed to process
|
||||||
|
* the configuration in order to detect default resource locations. If
|
||||||
|
* the XML-based loader detects default resource locations,
|
||||||
|
* an {@code info} message will be logged.</li>
|
||||||
|
* <li>Subsequently, the annotation-based loader will be allowed to
|
||||||
|
* process the configuration in order to detect default configuration classes.
|
||||||
|
* If the annotation-based loader detects default configuration
|
||||||
|
* classes, an {@code info} message will be logged.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param configAttributes the context configuration attributes to process
|
||||||
|
* @throws IllegalArgumentException if the supplied configuration attributes are
|
||||||
|
* <code>null</code>, or if the supplied configuration attributes include both
|
||||||
|
* resource locations and annotated classes
|
||||||
|
* @throws IllegalStateException if the XML-based loader detects default
|
||||||
|
* configuration classes; if the annotation-based loader detects default
|
||||||
|
* resource locations; if neither candidate loader detects defaults for the supplied
|
||||||
|
* context configuration; or if both candidate loaders detect defaults for the
|
||||||
|
* supplied context configuration
|
||||||
|
*/
|
||||||
|
public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
|
||||||
|
|
||||||
|
Assert.notNull(configAttributes, "configAttributes must not be null");
|
||||||
|
Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
|
||||||
|
"Cannot process locations AND classes for context "
|
||||||
|
+ "configuration %s; configure one or the other, but not both.", configAttributes));
|
||||||
|
|
||||||
|
// If the original locations or classes were not empty, there's no
|
||||||
|
// need to bother with default detection checks; just let the
|
||||||
|
// appropriate loader process the configuration.
|
||||||
|
if (configAttributes.hasLocations()) {
|
||||||
|
delegateProcessing(getXmlLoader(), configAttributes);
|
||||||
|
} else if (configAttributes.hasClasses()) {
|
||||||
|
delegateProcessing(getAnnotationConfigLoader(), configAttributes);
|
||||||
|
} else {
|
||||||
|
// Else attempt to detect defaults...
|
||||||
|
|
||||||
|
// Let the XML loader process the configuration.
|
||||||
|
delegateProcessing(getXmlLoader(), configAttributes);
|
||||||
|
boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
|
||||||
|
|
||||||
|
if (xmlLoaderDetectedDefaults) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
logger.info(String.format("%s detected default locations for context configuration %s.",
|
||||||
|
name(getXmlLoader()), configAttributes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configAttributes.hasClasses()) {
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"%s should NOT have detected default configuration classes for context configuration %s.",
|
||||||
|
name(getXmlLoader()), configAttributes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now let the annotation config loader process the configuration.
|
||||||
|
delegateProcessing(getAnnotationConfigLoader(), configAttributes);
|
||||||
|
|
||||||
|
if (configAttributes.hasClasses()) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
logger.info(String.format(
|
||||||
|
"%s detected default configuration classes for context configuration %s.",
|
||||||
|
name(getAnnotationConfigLoader()), configAttributes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"%s should NOT have detected default locations for context configuration %s.",
|
||||||
|
name(getAnnotationConfigLoader()), configAttributes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If neither loader detected defaults and no initializers were declared,
|
||||||
|
// throw an exception.
|
||||||
|
if (!configAttributes.hasResources() && ObjectUtils.isEmpty(configAttributes.getInitializers())) {
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers "
|
||||||
|
+ "were declared for context configuration %s", name(getXmlLoader()),
|
||||||
|
name(getAnnotationConfigLoader()), configAttributes));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
|
||||||
|
String message = String.format(
|
||||||
|
"Configuration error: both default locations AND default configuration classes "
|
||||||
|
+ "were detected for context configuration %s; configure one or the other, but not both.",
|
||||||
|
configAttributes);
|
||||||
|
logger.error(message);
|
||||||
|
throw new IllegalStateException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||||
|
* an {@link ApplicationContext}.
|
||||||
|
*
|
||||||
|
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||||
|
* default loaders for {@link #getXmlLoader() XML configuration files} and
|
||||||
|
* {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
|
||||||
|
* delegation algorithm is as follows:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>If the resource locations in the supplied {@code MergedContextConfiguration}
|
||||||
|
* are not empty and the annotated classes are empty,
|
||||||
|
* the XML-based loader will load the {@code ApplicationContext}.</li>
|
||||||
|
* <li>If the annotated classes in the supplied {@code MergedContextConfiguration}
|
||||||
|
* are not empty and the resource locations are empty,
|
||||||
|
* the annotation-based loader will load the {@code ApplicationContext}.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param mergedConfig the merged context configuration to use to load the application context
|
||||||
|
* @throws IllegalArgumentException if the supplied merged configuration is <code>null</code>
|
||||||
|
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
||||||
|
* {@code ApplicationContext} from the supplied merged context configuration
|
||||||
|
*/
|
||||||
|
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||||
|
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
||||||
|
|
||||||
|
List<SmartContextLoader> candidates = Arrays.asList(getXmlLoader(), getAnnotationConfigLoader());
|
||||||
|
|
||||||
|
for (SmartContextLoader loader : candidates) {
|
||||||
|
// Determine if each loader can load a context from the mergedConfig. If it
|
||||||
|
// can, let it; otherwise, keep iterating.
|
||||||
|
if (supports(loader, mergedConfig)) {
|
||||||
|
return delegateLoading(loader, mergedConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If neither of the candidates supports the mergedConfig based on resources but
|
||||||
|
// ACIs were declared, then delegate to the annotation config loader.
|
||||||
|
if (!mergedConfig.getContextInitializerClasses().isEmpty()) {
|
||||||
|
return delegateLoading(getAnnotationConfigLoader(), mergedConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"Neither %s nor %s was able to load an ApplicationContext from %s.", name(getXmlLoader()),
|
||||||
|
name(getAnnotationConfigLoader()), mergedConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ContextLoader -------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code AbstractDelegatingSmartContextLoader} does not support the
|
||||||
|
* {@link ContextLoader#processLocations(Class, String...)} method. Call
|
||||||
|
* {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public final String[] processLocations(Class<?> clazz, String... locations) {
|
||||||
|
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
|
||||||
|
+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code AbstractDelegatingSmartContextLoader} does not support the
|
||||||
|
* {@link ContextLoader#loadContext(String...) } method. Call
|
||||||
|
* {@link #loadContext(MergedContextConfiguration)} instead.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
public final ApplicationContext loadContext(String... locations) throws Exception {
|
||||||
|
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
|
||||||
|
+ "Call loadContext(MergedContextConfiguration) instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,25 +16,14 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
package org.springframework.test.context.support;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContextInitializer;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
|
||||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,7 +66,10 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Creates a {@link GenericApplicationContext} instance.</li>
|
* <li>Creates a {@link GenericApplicationContext} instance.</li>
|
||||||
* <li>Calls {@link #prepareContext(GenericApplicationContext, MergedContextConfiguration)}
|
* <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards
|
||||||
|
* compatibility with the {@link org.springframework.test.context.ContextLoader
|
||||||
|
* ContextLoader} SPI.</li>
|
||||||
|
* <li>Calls {@link #prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)}
|
||||||
* to allow for customizing the context before bean definitions are loaded.</li>
|
* to allow for customizing the context before bean definitions are loaded.</li>
|
||||||
* <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to allow for customizing the
|
* <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to allow for customizing the
|
||||||
* context's <code>DefaultListableBeanFactory</code>.</li>
|
* context's <code>DefaultListableBeanFactory</code>.</li>
|
||||||
|
|
@ -105,6 +97,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericApplicationContext context = new GenericApplicationContext();
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
|
prepareContext(context);
|
||||||
prepareContext(context, mergedConfig);
|
prepareContext(context, mergedConfig);
|
||||||
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
||||||
loadBeanDefinitions(context, mergedConfig);
|
loadBeanDefinitions(context, mergedConfig);
|
||||||
|
|
@ -183,72 +176,6 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
protected void prepareContext(GenericApplicationContext context) {
|
protected void prepareContext(GenericApplicationContext context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the {@link GenericApplicationContext} created by this
|
|
||||||
* {@code SmartContextLoader} <i>before</i> bean definitions are read.
|
|
||||||
*
|
|
||||||
* <p>The default implementation:
|
|
||||||
* <ul>
|
|
||||||
* <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards
|
|
||||||
* compatibility with the {@link org.springframework.test.context.ContextLoader
|
|
||||||
* ContextLoader} SPI.</li>
|
|
||||||
* <li>Sets the <em>active bean definition profiles</em> from the supplied
|
|
||||||
* <code>MergedContextConfiguration</code> in the
|
|
||||||
* {@link org.springframework.core.env.Environment Environment} of the context.</li>
|
|
||||||
* <li>Determines what (if any) context initializer classes have been supplied
|
|
||||||
* via the {@code MergedContextConfiguration} and
|
|
||||||
* {@linkplain ApplicationContextInitializer#initialize invokes each} with the
|
|
||||||
* given application context.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>Any {@code ApplicationContextInitializers} implementing
|
|
||||||
* {@link org.springframework.core.Ordered Ordered} or marked with {@link
|
|
||||||
* org.springframework.core.annotation.Order @Order} will be sorted appropriately.
|
|
||||||
*
|
|
||||||
* @param applicationContext the newly created application context
|
|
||||||
* @param mergedConfig the merged context configuration
|
|
||||||
* @see ApplicationContextInitializer#initialize(GenericApplicationContext)
|
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
|
||||||
* @see GenericApplicationContext#setAllowBeanDefinitionOverriding
|
|
||||||
* @see GenericApplicationContext#setResourceLoader
|
|
||||||
* @see GenericApplicationContext#setId
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void prepareContext(GenericApplicationContext applicationContext,
|
|
||||||
MergedContextConfiguration mergedConfig) {
|
|
||||||
|
|
||||||
prepareContext(applicationContext);
|
|
||||||
|
|
||||||
applicationContext.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
|
||||||
|
|
||||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
|
|
||||||
|
|
||||||
if (initializerClasses.size() == 0) {
|
|
||||||
// no ApplicationContextInitializers have been declared -> nothing to do
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
|
||||||
final Class<?> contextClass = applicationContext.getClass();
|
|
||||||
|
|
||||||
for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
|
|
||||||
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
|
|
||||||
ApplicationContextInitializer.class);
|
|
||||||
Assert.isAssignable(initializerContextClass, contextClass, String.format(
|
|
||||||
"Could not add context initializer [%s] since its generic parameter [%s] "
|
|
||||||
+ "is not assignable from the type of application context used by this "
|
|
||||||
+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
|
|
||||||
contextClass.getName()));
|
|
||||||
initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
|
|
||||||
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
|
|
||||||
initializer.initialize(applicationContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customize the internal bean factory of the ApplicationContext created by
|
* Customize the internal bean factory of the ApplicationContext created by
|
||||||
* this <code>ContextLoader</code>.
|
* this <code>ContextLoader</code>.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.support;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.FileSystemResourceLoader;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.mock.web.MockServletContext;
|
||||||
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
|
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document AbstractGenericWebContextLoader.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public abstract class AbstractGenericWebContextLoader extends AbstractContextLoader {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AbstractGenericWebContextLoader.class);
|
||||||
|
|
||||||
|
|
||||||
|
// --- SmartContextLoader -----------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document overridden loadContext(MergedContextConfiguration).
|
||||||
|
*
|
||||||
|
* @see org.springframework.test.context.SmartContextLoader#loadContext(org.springframework.test.context.MergedContextConfiguration)
|
||||||
|
*/
|
||||||
|
public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||||
|
|
||||||
|
if (!(mergedConfig instanceof WebMergedContextConfiguration)) {
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"Cannot load WebApplicationContext from non-web merged context configuration %s. "
|
||||||
|
+ "Consider annotating your test class with @WebAppConfiguration.", mergedConfig));
|
||||||
|
}
|
||||||
|
WebMergedContextConfiguration webMergedConfig = (WebMergedContextConfiguration) mergedConfig;
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("Loading WebApplicationContext for merged context configuration %s.",
|
||||||
|
webMergedConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
||||||
|
configureWebResources(context, webMergedConfig);
|
||||||
|
prepareContext(context, webMergedConfig);
|
||||||
|
customizeBeanFactory(context.getDefaultListableBeanFactory(), webMergedConfig);
|
||||||
|
loadBeanDefinitions(context, webMergedConfig);
|
||||||
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||||
|
customizeContext(context, webMergedConfig);
|
||||||
|
context.refresh();
|
||||||
|
context.registerShutdownHook();
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document configureWebResources().
|
||||||
|
*/
|
||||||
|
protected void configureWebResources(GenericWebApplicationContext context,
|
||||||
|
WebMergedContextConfiguration webMergedConfig) {
|
||||||
|
|
||||||
|
String resourceBasePath = webMergedConfig.getResourceBasePath();
|
||||||
|
ResourceLoader resourceLoader = resourceBasePath.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX) ? new DefaultResourceLoader()
|
||||||
|
: new FileSystemResourceLoader();
|
||||||
|
|
||||||
|
ServletContext servletContext = new MockServletContext(resourceBasePath, resourceLoader);
|
||||||
|
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
|
||||||
|
context.setServletContext(servletContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document customizeBeanFactory().
|
||||||
|
*/
|
||||||
|
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory,
|
||||||
|
WebMergedContextConfiguration webMergedConfig) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document loadBeanDefinitions().
|
||||||
|
*/
|
||||||
|
protected abstract void loadBeanDefinitions(GenericWebApplicationContext context,
|
||||||
|
WebMergedContextConfiguration webMergedConfig);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document customizeContext().
|
||||||
|
*/
|
||||||
|
protected void customizeContext(GenericWebApplicationContext context, WebMergedContextConfiguration webMergedConfig) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ContextLoader -------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document overridden loadContext(String...).
|
||||||
|
*
|
||||||
|
* @see org.springframework.test.context.ContextLoader#loadContext(java.lang.String[])
|
||||||
|
*/
|
||||||
|
public final ApplicationContext loadContext(String... locations) throws Exception {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"AbstractGenericWebContextLoader does not support the loadContext(String... locations) method");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,19 +16,13 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
package org.springframework.test.context.support;
|
||||||
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -89,80 +83,19 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
||||||
|
|
||||||
// --- AnnotationConfigContextLoader ---------------------------------------
|
// --- AnnotationConfigContextLoader ---------------------------------------
|
||||||
|
|
||||||
private boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
|
||||||
Assert.notNull(clazz, "Class must not be null");
|
|
||||||
int modifiers = clazz.getModifiers();
|
|
||||||
return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the supplied {@link Class} meets the criteria for being
|
|
||||||
* considered a <em>default configuration class</em> candidate.
|
|
||||||
*
|
|
||||||
* <p>Specifically, such candidates:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>must not be <code>null</code></li>
|
|
||||||
* <li>must not be <code>private</code></li>
|
|
||||||
* <li>must not be <code>final</code></li>
|
|
||||||
* <li>must be <code>static</code></li>
|
|
||||||
* <li>must be annotated with {@code @Configuration}</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param clazz the class to check
|
|
||||||
* @return <code>true</code> if the supplied class meets the candidate criteria
|
|
||||||
*/
|
|
||||||
private boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
|
||||||
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect the default configuration classes for the supplied test class.
|
* Detect the default configuration classes for the supplied test class.
|
||||||
*
|
*
|
||||||
* <p>The returned class array will contain all static inner classes of
|
* <p>The default implementation simply delegates to
|
||||||
* the supplied class that meet the requirements for {@code @Configuration}
|
* {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses(Class)}.
|
||||||
* class implementations as specified in the documentation for
|
|
||||||
* {@link Configuration @Configuration}.
|
|
||||||
*
|
*
|
||||||
* <p>The implementation of this method adheres to the contract defined in the
|
|
||||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
|
||||||
* SPI. Specifically, this method uses introspection to detect default
|
|
||||||
* configuration classes that comply with the constraints required of
|
|
||||||
* {@code @Configuration} class implementations. If a potential candidate
|
|
||||||
* configuration class does not meet these requirements, this method will log a
|
|
||||||
* warning, and the potential candidate class will be ignored.
|
|
||||||
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||||
* @return an array of default configuration classes, potentially empty but
|
* @return an array of default configuration classes, potentially empty but
|
||||||
* never <code>null</code>
|
* never <code>null</code>
|
||||||
|
* @see AnnotationConfigContextLoaderUtils
|
||||||
*/
|
*/
|
||||||
protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||||
Assert.notNull(declaringClass, "Declaring class must not be null");
|
return AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);
|
||||||
|
|
||||||
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
|
||||||
|
|
||||||
for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
|
|
||||||
if (isDefaultConfigurationClassCandidate(candidate)) {
|
|
||||||
configClasses.add(candidate);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format(
|
|
||||||
"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
|
|
||||||
+ "with @Configuration to be considered a default configuration class.",
|
|
||||||
candidate.getName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configClasses.isEmpty()) {
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
|
|
||||||
+ "%s does not declare any static, non-private, non-final, inner classes "
|
|
||||||
+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configClasses.toArray(new Class<?>[configClasses.size()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AbstractContextLoader -----------------------------------------------
|
// --- AbstractContextLoader -----------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.support;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document AnnotationConfigContextLoaderUtils.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
abstract class AnnotationConfigContextLoaderUtils {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AnnotationConfigContextLoaderUtils.class);
|
||||||
|
|
||||||
|
|
||||||
|
private AnnotationConfigContextLoaderUtils() {
|
||||||
|
/* no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
||||||
|
Assert.notNull(clazz, "Class must not be null");
|
||||||
|
int modifiers = clazz.getModifiers();
|
||||||
|
return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the supplied {@link Class} meets the criteria for being
|
||||||
|
* considered a <em>default configuration class</em> candidate.
|
||||||
|
*
|
||||||
|
* <p>Specifically, such candidates:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>must not be <code>null</code></li>
|
||||||
|
* <li>must not be <code>private</code></li>
|
||||||
|
* <li>must not be <code>final</code></li>
|
||||||
|
* <li>must be <code>static</code></li>
|
||||||
|
* <li>must be annotated with {@code @Configuration}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param clazz the class to check
|
||||||
|
* @return <code>true</code> if the supplied class meets the candidate criteria
|
||||||
|
*/
|
||||||
|
private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
||||||
|
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect the default configuration classes for the supplied test class.
|
||||||
|
*
|
||||||
|
* <p>The returned class array will contain all static inner classes of
|
||||||
|
* the supplied class that meet the requirements for {@code @Configuration}
|
||||||
|
* class implementations as specified in the documentation for
|
||||||
|
* {@link Configuration @Configuration}.
|
||||||
|
*
|
||||||
|
* <p>The implementation of this method adheres to the contract defined in the
|
||||||
|
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
||||||
|
* SPI. Specifically, this method uses introspection to detect default
|
||||||
|
* configuration classes that comply with the constraints required of
|
||||||
|
* {@code @Configuration} class implementations. If a potential candidate
|
||||||
|
* configuration class does not meet these requirements, this method will log a
|
||||||
|
* warning, and the potential candidate class will be ignored.
|
||||||
|
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||||
|
* @return an array of default configuration classes, potentially empty but
|
||||||
|
* never <code>null</code>
|
||||||
|
*/
|
||||||
|
static Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||||
|
Assert.notNull(declaringClass, "Declaring class must not be null");
|
||||||
|
|
||||||
|
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
||||||
|
|
||||||
|
for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
|
||||||
|
if (isDefaultConfigurationClassCandidate(candidate)) {
|
||||||
|
configClasses.add(candidate);
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format(
|
||||||
|
"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
|
||||||
|
+ "with @Configuration to be considered a default configuration class.",
|
||||||
|
candidate.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configClasses.isEmpty()) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
|
||||||
|
+ "%s does not declare any static, non-private, non-final, inner classes "
|
||||||
|
+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return configClasses.toArray(new Class<?>[configClasses.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.support;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||||
|
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||||
|
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document AnnotationConfigWebContextLoader.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class AnnotationConfigWebContextLoader extends AbstractGenericWebContextLoader {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AnnotationConfigWebContextLoader.class);
|
||||||
|
|
||||||
|
|
||||||
|
// --- SmartContextLoader -----------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process <em>annotated classes</em> in the supplied {@link ContextConfigurationAttributes}.
|
||||||
|
*
|
||||||
|
* <p>If the <em>annotated classes</em> are <code>null</code> or empty and
|
||||||
|
* {@link #isGenerateDefaultLocations()} returns <code>true</code>, this
|
||||||
|
* <code>SmartContextLoader</code> will attempt to {@link
|
||||||
|
* #detectDefaultConfigurationClasses detect default configuration classes}.
|
||||||
|
* If defaults are detected they will be
|
||||||
|
* {@link ContextConfigurationAttributes#setClasses(Class[]) set} in the
|
||||||
|
* supplied configuration attributes. Otherwise, properties in the supplied
|
||||||
|
* configuration attributes will not be modified.
|
||||||
|
*
|
||||||
|
* @param configAttributes the context configuration attributes to process
|
||||||
|
* @see org.springframework.test.context.SmartContextLoader#processContextConfiguration(ContextConfigurationAttributes)
|
||||||
|
* @see #isGenerateDefaultLocations()
|
||||||
|
* @see #detectDefaultConfigurationClasses(Class)
|
||||||
|
*/
|
||||||
|
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||||
|
if (ObjectUtils.isEmpty(configAttributes.getClasses()) && isGenerateDefaultLocations()) {
|
||||||
|
Class<?>[] defaultConfigClasses = detectDefaultConfigurationClasses(configAttributes.getDeclaringClass());
|
||||||
|
configAttributes.setClasses(defaultConfigClasses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect the default configuration classes for the supplied test class.
|
||||||
|
*
|
||||||
|
* <p>The default implementation simply delegates to
|
||||||
|
* {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses(Class)}.
|
||||||
|
*
|
||||||
|
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||||
|
* @return an array of default configuration classes, potentially empty but
|
||||||
|
* never <code>null</code>
|
||||||
|
* @see AnnotationConfigContextLoaderUtils
|
||||||
|
*/
|
||||||
|
protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||||
|
return AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- AbstractContextLoader -----------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code AnnotationConfigWebContextLoader} should be used as a
|
||||||
|
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
|
||||||
|
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
|
||||||
|
* Consequently, this method is not supported.
|
||||||
|
*
|
||||||
|
* @see AbstractContextLoader#modifyLocations
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String[] modifyLocations(Class<?> clazz, String... locations) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"AnnotationConfigWebContextLoader does not support the modifyLocations(Class, String...) method");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code AnnotationConfigWebContextLoader} should be used as a
|
||||||
|
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
|
||||||
|
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
|
||||||
|
* Consequently, this method is not supported.
|
||||||
|
*
|
||||||
|
* @see AbstractContextLoader#generateDefaultLocations
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String[] generateDefaultLocations(Class<?> clazz) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"AnnotationConfigWebContextLoader does not support the generateDefaultLocations(Class) method");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code AnnotationConfigWebContextLoader} should be used as a
|
||||||
|
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
|
||||||
|
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
|
||||||
|
* Consequently, this method is not supported.
|
||||||
|
*
|
||||||
|
* @see AbstractContextLoader#getResourceSuffix
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getResourceSuffix() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"AnnotationConfigWebContextLoader does not support the getResourceSuffix() method");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- AbstractGenericWebContextLoader -------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register classes in the supplied {@link GenericWebApplicationContext context}
|
||||||
|
* from the classes in the supplied {@link WebMergedContextConfiguration}.
|
||||||
|
*
|
||||||
|
* <p>Each class must represent an <em>annotated class</em>. An
|
||||||
|
* {@link AnnotatedBeanDefinitionReader} is used to register the appropriate
|
||||||
|
* bean definitions.
|
||||||
|
*
|
||||||
|
* @param context the context in which the annotated classes should be registered
|
||||||
|
* @param webMergedConfig the merged configuration from which the classes should be retrieved
|
||||||
|
*
|
||||||
|
* @see AbstractGenericWebContextLoader#loadBeanDefinitions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void loadBeanDefinitions(GenericWebApplicationContext context,
|
||||||
|
WebMergedContextConfiguration webMergedConfig) {
|
||||||
|
Class<?>[] annotatedClasses = webMergedConfig.getClasses();
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Registering annotated classes: " + ObjectUtils.nullSafeToString(annotatedClasses));
|
||||||
|
}
|
||||||
|
new AnnotatedBeanDefinitionReader(context).register(annotatedClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,263 +16,32 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
package org.springframework.test.context.support;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
|
||||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
|
||||||
import org.springframework.test.context.ContextLoader;
|
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
|
||||||
import org.springframework.test.context.SmartContextLoader;
|
import org.springframework.test.context.SmartContextLoader;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code DelegatingSmartContextLoader} is an implementation of the {@link SmartContextLoader}
|
* {@code DelegatingSmartContextLoader} is a concrete implementation of
|
||||||
* SPI that delegates to a set of <em>candidate</em> SmartContextLoaders (i.e.,
|
* {@link AbstractDelegatingSmartContextLoader} that delegates to a
|
||||||
* {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}) to
|
* {@link GenericXmlContextLoader} and an {@link AnnotationConfigContextLoader}.
|
||||||
* determine which context loader is appropriate for a given test class's configuration.
|
|
||||||
* Each candidate is given a chance to {@link #processContextConfiguration process} the
|
|
||||||
* {@link ContextConfigurationAttributes} for each class in the test class hierarchy that
|
|
||||||
* is annotated with {@link ContextConfiguration @ContextConfiguration}, and the candidate
|
|
||||||
* that supports the merged, processed configuration will be used to actually
|
|
||||||
* {@link #loadContext load} the context.
|
|
||||||
*
|
|
||||||
* <p>Placing an empty {@code @ContextConfiguration} annotation on a test class signals
|
|
||||||
* that default resource locations (i.e., XML configuration files) or default
|
|
||||||
* {@link org.springframework.context.annotation.Configuration configuration classes}
|
|
||||||
* should be detected. Furthermore, if a specific {@link ContextLoader} or
|
|
||||||
* {@link SmartContextLoader} is not explicitly declared via
|
|
||||||
* {@code @ContextConfiguration}, {@code DelegatingSmartContextLoader} will be used as
|
|
||||||
* the default loader, thus providing automatic support for either XML configuration
|
|
||||||
* files or annotated classes, but not both simultaneously.
|
|
||||||
*
|
|
||||||
* <p>As of Spring 3.2, a test class may optionally declare neither XML configuration
|
|
||||||
* files nor annotated classes and instead declare only {@linkplain
|
|
||||||
* ContextConfiguration#initializers application context initializers}. In such
|
|
||||||
* cases, an attempt will still be made to detect defaults, but their absence will
|
|
||||||
* not result an an exception.
|
|
||||||
*
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 3.1
|
* @since 3.1
|
||||||
* @see SmartContextLoader
|
* @see SmartContextLoader
|
||||||
|
* @see AbstractDelegatingSmartContextLoader
|
||||||
* @see GenericXmlContextLoader
|
* @see GenericXmlContextLoader
|
||||||
* @see AnnotationConfigContextLoader
|
* @see AnnotationConfigContextLoader
|
||||||
*/
|
*/
|
||||||
public class DelegatingSmartContextLoader implements SmartContextLoader {
|
public class DelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(DelegatingSmartContextLoader.class);
|
|
||||||
|
|
||||||
private final SmartContextLoader xmlLoader = new GenericXmlContextLoader();
|
private final SmartContextLoader xmlLoader = new GenericXmlContextLoader();
|
||||||
private final SmartContextLoader annotationConfigLoader = new AnnotationConfigContextLoader();
|
private final SmartContextLoader annotationConfigLoader = new AnnotationConfigContextLoader();
|
||||||
|
|
||||||
|
|
||||||
// --- SmartContextLoader --------------------------------------------------
|
protected SmartContextLoader getXmlLoader() {
|
||||||
|
return this.xmlLoader;
|
||||||
private static String name(SmartContextLoader loader) {
|
|
||||||
return loader.getClass().getSimpleName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
|
protected SmartContextLoader getAnnotationConfigLoader() {
|
||||||
if (logger.isDebugEnabled()) {
|
return this.annotationConfigLoader;
|
||||||
logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader),
|
|
||||||
configAttributes));
|
|
||||||
}
|
|
||||||
loader.processContextConfiguration(configAttributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
|
|
||||||
throws Exception {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
|
||||||
}
|
|
||||||
return loader.loadContext(mergedConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
|
||||||
if (loader instanceof AnnotationConfigContextLoader) {
|
|
||||||
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
|
||||||
} else {
|
|
||||||
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
|
|
||||||
* {@link ContextConfigurationAttributes}.
|
|
||||||
*
|
|
||||||
* <p>Delegation is based on explicit knowledge of the implementations of
|
|
||||||
* {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}.
|
|
||||||
* Specifically, the delegation algorithm is as follows:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>If the resource locations or annotated classes in the supplied
|
|
||||||
* {@code ContextConfigurationAttributes} are not empty, the appropriate
|
|
||||||
* candidate loader will be allowed to process the configuration <em>as is</em>,
|
|
||||||
* without any checks for detection of defaults.</li>
|
|
||||||
* <li>Otherwise, {@code GenericXmlContextLoader} will be allowed to process
|
|
||||||
* the configuration in order to detect default resource locations. If
|
|
||||||
* {@code GenericXmlContextLoader} detects default resource locations,
|
|
||||||
* an {@code info} message will be logged.</li>
|
|
||||||
* <li>Subsequently, {@code AnnotationConfigContextLoader} will be allowed to
|
|
||||||
* process the configuration in order to detect default configuration classes.
|
|
||||||
* If {@code AnnotationConfigContextLoader} detects default configuration
|
|
||||||
* classes, an {@code info} message will be logged.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param configAttributes the context configuration attributes to process
|
|
||||||
* @throws IllegalArgumentException if the supplied configuration attributes are
|
|
||||||
* <code>null</code>, or if the supplied configuration attributes include both
|
|
||||||
* resource locations and annotated classes
|
|
||||||
* @throws IllegalStateException if {@code GenericXmlContextLoader} detects default
|
|
||||||
* configuration classes; if {@code AnnotationConfigContextLoader} detects default
|
|
||||||
* resource locations; if neither candidate loader detects defaults for the supplied
|
|
||||||
* context configuration; or if both candidate loaders detect defaults for the
|
|
||||||
* supplied context configuration
|
|
||||||
*/
|
|
||||||
public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
|
|
||||||
|
|
||||||
Assert.notNull(configAttributes, "configAttributes must not be null");
|
|
||||||
Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
|
|
||||||
"Cannot process locations AND classes for context "
|
|
||||||
+ "configuration %s; configure one or the other, but not both.", configAttributes));
|
|
||||||
|
|
||||||
// If the original locations or classes were not empty, there's no
|
|
||||||
// need to bother with default detection checks; just let the
|
|
||||||
// appropriate loader process the configuration.
|
|
||||||
if (configAttributes.hasLocations()) {
|
|
||||||
delegateProcessing(xmlLoader, configAttributes);
|
|
||||||
} else if (configAttributes.hasClasses()) {
|
|
||||||
delegateProcessing(annotationConfigLoader, configAttributes);
|
|
||||||
} else {
|
|
||||||
// Else attempt to detect defaults...
|
|
||||||
|
|
||||||
// Let the XML loader process the configuration.
|
|
||||||
delegateProcessing(xmlLoader, configAttributes);
|
|
||||||
boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
|
|
||||||
|
|
||||||
if (xmlLoaderDetectedDefaults) {
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info(String.format("%s detected default locations for context configuration %s.",
|
|
||||||
name(xmlLoader), configAttributes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configAttributes.hasClasses()) {
|
|
||||||
throw new IllegalStateException(String.format(
|
|
||||||
"%s should NOT have detected default configuration classes for context configuration %s.",
|
|
||||||
name(xmlLoader), configAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now let the annotation config loader process the configuration.
|
|
||||||
delegateProcessing(annotationConfigLoader, configAttributes);
|
|
||||||
|
|
||||||
if (configAttributes.hasClasses()) {
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info(String.format(
|
|
||||||
"%s detected default configuration classes for context configuration %s.",
|
|
||||||
name(annotationConfigLoader), configAttributes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
|
|
||||||
throw new IllegalStateException(String.format(
|
|
||||||
"%s should NOT have detected default locations for context configuration %s.",
|
|
||||||
name(annotationConfigLoader), configAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If neither loader detected defaults and no initializers were declared,
|
|
||||||
// throw an exception.
|
|
||||||
if (!configAttributes.hasResources() && ObjectUtils.isEmpty(configAttributes.getInitializers())) {
|
|
||||||
throw new IllegalStateException(String.format(
|
|
||||||
"Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers "
|
|
||||||
+ "were declared for context configuration %s", name(xmlLoader),
|
|
||||||
name(annotationConfigLoader), configAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
|
|
||||||
String message = String.format(
|
|
||||||
"Configuration error: both default locations AND default configuration classes "
|
|
||||||
+ "were detected for context configuration %s; configure one or the other, but not both.",
|
|
||||||
configAttributes);
|
|
||||||
logger.error(message);
|
|
||||||
throw new IllegalStateException(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
|
||||||
* an {@link ApplicationContext}.
|
|
||||||
*
|
|
||||||
* <p>Delegation is based on explicit knowledge of the implementations of
|
|
||||||
* {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}.
|
|
||||||
* Specifically, the delegation algorithm is as follows:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>If the resource locations in the supplied {@code MergedContextConfiguration}
|
|
||||||
* are not empty and the annotated classes are empty,
|
|
||||||
* {@code GenericXmlContextLoader} will load the {@code ApplicationContext}.</li>
|
|
||||||
* <li>If the annotated classes in the supplied {@code MergedContextConfiguration}
|
|
||||||
* are not empty and the resource locations are empty,
|
|
||||||
* {@code AnnotationConfigContextLoader} will load the {@code ApplicationContext}.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param mergedConfig the merged context configuration to use to load the application context
|
|
||||||
* @throws IllegalArgumentException if the supplied merged configuration is <code>null</code>
|
|
||||||
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
|
||||||
* {@code ApplicationContext} from the supplied merged context configuration
|
|
||||||
*/
|
|
||||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
|
||||||
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
|
||||||
|
|
||||||
List<SmartContextLoader> candidates = Arrays.asList(xmlLoader, annotationConfigLoader);
|
|
||||||
|
|
||||||
for (SmartContextLoader loader : candidates) {
|
|
||||||
// Determine if each loader can load a context from the mergedConfig. If it
|
|
||||||
// can, let it; otherwise, keep iterating.
|
|
||||||
if (supports(loader, mergedConfig)) {
|
|
||||||
return delegateLoading(loader, mergedConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If neither of the candidates supports the mergedConfig based on resources but
|
|
||||||
// ACIs were declared, then delegate to the ACCL.
|
|
||||||
if (!mergedConfig.getContextInitializerClasses().isEmpty()) {
|
|
||||||
return delegateLoading(annotationConfigLoader, mergedConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException(String.format(
|
|
||||||
"Neither %s nor %s was able to load an ApplicationContext from %s.", name(xmlLoader),
|
|
||||||
name(annotationConfigLoader), mergedConfig));
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- ContextLoader -------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code DelegatingSmartContextLoader} does not support the
|
|
||||||
* {@link ContextLoader#processLocations(Class, String...)} method. Call
|
|
||||||
* {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
|
|
||||||
* @throws UnsupportedOperationException
|
|
||||||
*/
|
|
||||||
public String[] processLocations(Class<?> clazz, String... locations) {
|
|
||||||
throw new UnsupportedOperationException("DelegatingSmartContextLoader does not support the ContextLoader SPI. "
|
|
||||||
+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code DelegatingSmartContextLoader} does not support the
|
|
||||||
* {@link ContextLoader#loadContext(String...) } method. Call
|
|
||||||
* {@link #loadContext(MergedContextConfiguration)} instead.
|
|
||||||
* @throws UnsupportedOperationException
|
|
||||||
*/
|
|
||||||
public ApplicationContext loadContext(String... locations) throws Exception {
|
|
||||||
throw new UnsupportedOperationException("DelegatingSmartContextLoader does not support the ContextLoader SPI. "
|
|
||||||
+ "Call loadContext(MergedContextConfiguration) instead.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.support;
|
||||||
|
|
||||||
|
import org.springframework.test.context.SmartContextLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code WebDelegatingSmartContextLoader} is a concrete implementation of
|
||||||
|
* {@link AbstractDelegatingSmartContextLoader} that delegates to an
|
||||||
|
* {@link XmlWebContextLoader} and an {@link AnnotationConfigWebContextLoader}.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
* @see SmartContextLoader
|
||||||
|
* @see AbstractDelegatingSmartContextLoader
|
||||||
|
* @see XmlWebContextLoader
|
||||||
|
* @see AnnotationConfigWebContextLoader
|
||||||
|
*/
|
||||||
|
public class WebDelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
|
||||||
|
|
||||||
|
private final SmartContextLoader xmlLoader = new XmlWebContextLoader();
|
||||||
|
private final SmartContextLoader annotationConfigLoader = new AnnotationConfigWebContextLoader();
|
||||||
|
|
||||||
|
|
||||||
|
protected SmartContextLoader getXmlLoader() {
|
||||||
|
return this.xmlLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SmartContextLoader getAnnotationConfigLoader() {
|
||||||
|
return this.annotationConfigLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.support;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||||
|
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||||
|
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document XmlWebContextLoader.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class XmlWebContextLoader extends AbstractGenericWebContextLoader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns "<code>-context.xml</code>".
|
||||||
|
*/
|
||||||
|
protected String getResourceSuffix() {
|
||||||
|
return "-context.xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document overridden loadBeanDefinitions().
|
||||||
|
*
|
||||||
|
* @see org.springframework.test.context.support.AbstractGenericWebContextLoader#loadBeanDefinitions(org.springframework.web.context.support.GenericWebApplicationContext, org.springframework.test.context.web.WebMergedContextConfiguration)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void loadBeanDefinitions(GenericWebApplicationContext context,
|
||||||
|
WebMergedContextConfiguration webMergedConfig) {
|
||||||
|
new XmlBeanDefinitionReader(context).loadBeanDefinitions(webMergedConfig.getLocations());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.web;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document WebAppConfiguration.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Inherited
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface WebAppConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root directory of the web application (i.e., WAR); should not end with a slash.
|
||||||
|
*
|
||||||
|
* <p>Defaults to {@code "src/main/webapp"}.
|
||||||
|
*/
|
||||||
|
String value() default "src/main/webapp";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.web;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.core.style.ToStringCreator;
|
||||||
|
import org.springframework.test.context.ContextLoader;
|
||||||
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document WebMergedContextConfiguration.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class WebMergedContextConfiguration extends MergedContextConfiguration {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7323361588604247458L;
|
||||||
|
|
||||||
|
private final String resourceBasePath;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document WebMergedContextConfiguration constructor.
|
||||||
|
*/
|
||||||
|
public WebMergedContextConfiguration(
|
||||||
|
Class<?> testClass,
|
||||||
|
String[] locations,
|
||||||
|
Class<?>[] classes,
|
||||||
|
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses,
|
||||||
|
String[] activeProfiles, String resourceBasePath, ContextLoader contextLoader) {
|
||||||
|
|
||||||
|
super(testClass, locations, classes, contextInitializerClasses, activeProfiles, contextLoader);
|
||||||
|
|
||||||
|
this.resourceBasePath = !StringUtils.hasText(resourceBasePath) ? "" : resourceBasePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document getResourceBasePath().
|
||||||
|
*/
|
||||||
|
public String getResourceBasePath() {
|
||||||
|
return this.resourceBasePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique hash code for all properties of this
|
||||||
|
* {@code WebMergedContextConfiguration} excluding the
|
||||||
|
* {@linkplain #getTestClass() test class}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = prime * result + resourceBasePath.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the supplied object is equal to this {@code WebMergedContextConfiguration}
|
||||||
|
* instance by comparing both object's {@linkplain #getLocations() locations},
|
||||||
|
* {@linkplain #getClasses() annotated classes},
|
||||||
|
* {@linkplain #getContextInitializerClasses() context initializer classes},
|
||||||
|
* {@linkplain #getActiveProfiles() active profiles},
|
||||||
|
* {@linkplain #getResourceBasePath() resource base path}, and the fully
|
||||||
|
* qualified names of their {@link #getContextLoader() ContextLoaders}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof WebMergedContextConfiguration)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final WebMergedContextConfiguration that = (WebMergedContextConfiguration) obj;
|
||||||
|
|
||||||
|
return super.equals(that) && this.getResourceBasePath().equals(that.getResourceBasePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a String representation of the {@linkplain #getTestClass() test class},
|
||||||
|
* {@linkplain #getLocations() locations}, {@linkplain #getClasses() annotated classes},
|
||||||
|
* {@linkplain #getContextInitializerClasses() context initializer classes},
|
||||||
|
* {@linkplain #getActiveProfiles() active profiles},
|
||||||
|
* {@linkplain #getResourceBasePath() resource base path}, and the name of the
|
||||||
|
* {@link #getContextLoader() ContextLoader}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringCreator(this)//
|
||||||
|
.append("testClass", getTestClass())//
|
||||||
|
.append("locations", ObjectUtils.nullSafeToString(getLocations()))//
|
||||||
|
.append("classes", ObjectUtils.nullSafeToString(getClasses()))//
|
||||||
|
.append("contextInitializerClasses", ObjectUtils.nullSafeToString(getContextInitializerClasses()))//
|
||||||
|
.append("activeProfiles", ObjectUtils.nullSafeToString(getActiveProfiles()))//
|
||||||
|
.append("resourceBasePath", getResourceBasePath())//
|
||||||
|
.append("contextLoader", nullSafeToString(getContextLoader()))//
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.web;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.mock.web.MockServletContext;
|
||||||
|
import org.springframework.test.context.TestContext;
|
||||||
|
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document WebTestExecutionListener.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class WebTestExecutionListener extends AbstractTestExecutionListener {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(WebTestExecutionListener.class);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document overridden prepareTestInstance().
|
||||||
|
*
|
||||||
|
* @see org.springframework.test.context.support.AbstractTestExecutionListener#prepareTestInstance(org.springframework.test.context.TestContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void prepareTestInstance(TestContext testContext) throws Exception {
|
||||||
|
setUpRequestContextIfNecessary(testContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document overridden beforeTestMethod().
|
||||||
|
*
|
||||||
|
* @see org.springframework.test.context.support.AbstractTestExecutionListener#beforeTestMethod(org.springframework.test.context.TestContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||||
|
setUpRequestContextIfNecessary(testContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document setUpRequestContext().
|
||||||
|
*
|
||||||
|
* @param testContext
|
||||||
|
* @param servletContext
|
||||||
|
*/
|
||||||
|
private void setUpRequestContextIfNecessary(TestContext testContext) {
|
||||||
|
|
||||||
|
ApplicationContext context = testContext.getApplicationContext();
|
||||||
|
|
||||||
|
if (context instanceof WebApplicationContext) {
|
||||||
|
WebApplicationContext wac = (WebApplicationContext) context;
|
||||||
|
ServletContext servletContext = wac.getServletContext();
|
||||||
|
if (!(servletContext instanceof MockServletContext)) {
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"The WebApplicationContext for test context %s must be configured with a MockServletContext.",
|
||||||
|
testContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format(
|
||||||
|
"Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.",
|
||||||
|
testContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() == null) {
|
||||||
|
MockServletContext mockServletContext = (MockServletContext) servletContext;
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest(mockServletContext);
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);
|
||||||
|
|
||||||
|
RequestContextHolder.setRequestAttributes(servletWebRequest);
|
||||||
|
|
||||||
|
if (wac instanceof ConfigurableApplicationContext) {
|
||||||
|
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) wac;
|
||||||
|
ConfigurableListableBeanFactory bf = configurableApplicationContext.getBeanFactory();
|
||||||
|
bf.registerResolvableDependency(MockHttpServletResponse.class, response);
|
||||||
|
bf.registerResolvableDependency(ServletWebRequest.class, servletWebRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO [SPR-5243] Document overridden afterTestMethod().
|
||||||
|
*
|
||||||
|
* @see org.springframework.test.context.support.AbstractTestExecutionListener#afterTestMethod(org.springframework.test.context.TestContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
|
||||||
|
}
|
||||||
|
RequestContextHolder.resetRequestAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -42,7 +42,7 @@ public class TestExecutionListenersTests {
|
||||||
@Test
|
@Test
|
||||||
public void verifyNumDefaultListenersRegistered() throws Exception {
|
public void verifyNumDefaultListenersRegistered() throws Exception {
|
||||||
TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
|
TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
|
||||||
assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 3,
|
assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 4,
|
||||||
testContextManager.getTestExecutionListeners().size());
|
testContextManager.getTestExecutionListeners().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.web;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.mock.web.MockServletContext;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.web.context.ServletContextAware;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
public abstract class AbstractBasicWacTests implements ServletContextAware {
|
||||||
|
|
||||||
|
protected ServletContext servletContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected WebApplicationContext wac;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected MockServletContext mockServletContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected MockHttpServletRequest request;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected MockHttpServletResponse response;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected ServletWebRequest webRequest;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected String foo;
|
||||||
|
|
||||||
|
|
||||||
|
public void setServletContext(ServletContext servletContext) {
|
||||||
|
this.servletContext = servletContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basicWacFeatures() throws Exception {
|
||||||
|
assertNotNull("ServletContext should be set in the WAC.", wac.getServletContext());
|
||||||
|
|
||||||
|
assertNotNull("ServletContext should have been set via ServletContextAware.", servletContext);
|
||||||
|
|
||||||
|
assertNotNull("ServletContext should have been autowired from the WAC.", mockServletContext);
|
||||||
|
assertNotNull("MockHttpServletRequest should have been autowired from the WAC.", request);
|
||||||
|
assertNotNull("MockHttpServletResponse should have been autowired from the WAC.", response);
|
||||||
|
assertNotNull("ServletWebRequest should have been autowired from the WAC.", webRequest);
|
||||||
|
|
||||||
|
Object rootWac = mockServletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||||
|
assertNotNull("Root WAC must be stored in the ServletContext as: "
|
||||||
|
+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootWac);
|
||||||
|
assertSame("test WAC and Root WAC in ServletContext must be the same object.", wac, rootWac);
|
||||||
|
assertSame("ServletContext instances must be the same object.", mockServletContext, wac.getServletContext());
|
||||||
|
assertSame("ServletContext in the WAC and in the mock request", mockServletContext, request.getServletContext());
|
||||||
|
|
||||||
|
assertEquals("Getting real path for ServletContext resource.",
|
||||||
|
new File("src/main/webapp/index.jsp").getCanonicalPath(), mockServletContext.getRealPath("index.jsp"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.web;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@ContextConfiguration
|
||||||
|
public class BasicAnnotationConfigWacTests extends AbstractBasicWacTests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public String foo() {
|
||||||
|
return "enigma";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fooEnigmaAutowired() {
|
||||||
|
assertEquals("enigma", foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -13,12 +13,24 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.test.web.mock.servlet.samples.context;
|
|
||||||
|
|
||||||
class WebContextLoader extends GenericWebContextLoader {
|
package org.springframework.test.context.web;
|
||||||
|
|
||||||
public WebContextLoader() {
|
import static org.junit.Assert.*;
|
||||||
super("src/test/resources/META-INF/web-resources", false);
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@ContextConfiguration
|
||||||
|
public class BasicXmlWacTests extends AbstractBasicWacTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fooBarAutowired() {
|
||||||
|
assertEquals("bar", foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 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.
|
||||||
|
* 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.springframework.test.context.web;
|
||||||
|
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Suite;
|
||||||
|
import org.junit.runners.Suite.SuiteClasses;
|
||||||
|
import org.springframework.test.context.ContextLoader;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience test suite for integration tests that verify support for
|
||||||
|
* {@link WebApplicationContext} {@linkplain ContextLoader context loaders}
|
||||||
|
* in the TestContext framework.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@RunWith(Suite.class)
|
||||||
|
// Note: the following 'multi-line' layout is for enhanced code readability.
|
||||||
|
@SuiteClasses({//
|
||||||
|
BasicXmlWacTests.class,//
|
||||||
|
BasicAnnotationConfigWacTests.class //
|
||||||
|
})
|
||||||
|
public class WebContextLoaderTestSuite {
|
||||||
|
}
|
||||||
|
|
@ -45,6 +45,10 @@
|
||||||
<level value="warn" />
|
<level value="warn" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
|
<logger name="org.springframework.test.context.web">
|
||||||
|
<level value="warn" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
<logger name="org.springframework.test.context">
|
<logger name="org.springframework.test.context">
|
||||||
<level value="warn" />
|
<level value="warn" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
|
||||||
|
<bean id="foo" class="java.lang.String" c:_="bar" />
|
||||||
|
|
||||||
|
</beans>
|
||||||
Loading…
Reference in New Issue