DATACMNS-993 - Clean up class loader hacking in tests.
ClassLoaderRule with @ClassLoaderConfiguration allows easy creation FilteringClassLoader. Changed usage pattern of ClassUtils.isPresent(…) in order to ease testing. Copied the ShadowingClassloader from SpringFramework to get a constructor that doesn't shadow anything by default. Original pull request: #202.
This commit is contained in:
committed by
Oliver Gierke
parent
562b6665a3
commit
65734739bd
@@ -24,7 +24,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
|
||||
|
||||
/**
|
||||
* Helper methods for web integration testing.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class WebTestUtils {
|
||||
@@ -41,13 +41,28 @@ public class WebTestUtils {
|
||||
|
||||
/**
|
||||
* Creates a {@link WebApplicationContext} from the given configuration classes.
|
||||
*
|
||||
*
|
||||
* @param configClasses
|
||||
* @return
|
||||
*/
|
||||
public static WebApplicationContext createApplicationContext(Class<?>... configClasses) {
|
||||
return createApplicationContext(null, configClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link WebApplicationContext} from the given configuration classes.
|
||||
*
|
||||
* @param classLoader gets set as ClassLoader in the context
|
||||
* @param configClasses
|
||||
* @return
|
||||
*/
|
||||
public static WebApplicationContext createApplicationContext(ClassLoader classLoader, Class<?>... configClasses) {
|
||||
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
if (classLoader != null) {
|
||||
context.setClassLoader(classLoader);
|
||||
}
|
||||
|
||||
context.setServletContext(new MockServletContext());
|
||||
|
||||
for (Class<?> configClass : configClasses) {
|
||||
|
||||
@@ -20,56 +20,62 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.classloadersupport.ClassLoaderConfiguration;
|
||||
import org.springframework.data.classloadersupport.ClassLoaderRule;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
|
||||
import org.springframework.data.web.PagedResourcesAssemblerArgumentResolver;
|
||||
import org.springframework.data.web.SortHandlerMethodArgumentResolver;
|
||||
import org.springframework.data.web.WebTestUtils;
|
||||
import org.springframework.data.web.config.EnableSpringDataWebSupport.SpringDataWebConfigurationImportSelector;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link EnableSpringDataWebSupport}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
|
||||
@ClassLoaderConfiguration(shadowPackage = {
|
||||
WebMvcConfigurationSupport.class,
|
||||
EnableSpringDataWebSupport.class,
|
||||
EnableSpringDataWebSupportIntegrationTests.SampleConfig.class})
|
||||
public class EnableSpringDataWebSupportIntegrationTests {
|
||||
|
||||
private static final String HATEOAS = "HATEOAS_PRESENT";
|
||||
private static final String JACKSON = "JACKSON_PRESENT";
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableSpringDataWebSupport
|
||||
static class SampleConfig {
|
||||
|
||||
public @Bean SampleController controller() {
|
||||
public
|
||||
@Bean
|
||||
SampleController controller() {
|
||||
return new SampleController();
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
reEnable(HATEOAS);
|
||||
reEnable(JACKSON);
|
||||
}
|
||||
@Rule public ClassLoaderRule classLoaderRule = new ClassLoaderRule();
|
||||
|
||||
|
||||
@Test // DATACMNS-330
|
||||
public void registersBasicBeanDefinitions() throws Exception {
|
||||
@@ -94,11 +100,11 @@ public class EnableSpringDataWebSupportIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATACMNS-330
|
||||
@ClassLoaderConfiguration(hidePackage = Link.class)
|
||||
public void doesNotRegisterHateoasSpecificComponentsIfHateoasNotPresent() throws Exception {
|
||||
|
||||
hide(HATEOAS);
|
||||
ApplicationContext context = WebTestUtils.createApplicationContext(classLoaderRule.classLoader, SampleConfig.class);
|
||||
|
||||
ApplicationContext context = WebTestUtils.createApplicationContext(SampleConfig.class);
|
||||
List<String> names = Arrays.asList(context.getBeanDefinitionNames());
|
||||
|
||||
assertThat(names).contains("pageableResolver", "sortResolver");
|
||||
@@ -115,11 +121,11 @@ public class EnableSpringDataWebSupportIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATACMNS-475
|
||||
@ClassLoaderConfiguration(hidePackage = com.fasterxml.jackson.databind.ObjectMapper.class)
|
||||
public void doesNotRegisterJacksonSpecificComponentsIfJacksonNotPresent() throws Exception {
|
||||
|
||||
hide(JACKSON);
|
||||
ApplicationContext context = WebTestUtils.createApplicationContext(classLoaderRule.classLoader, SampleConfig.class);
|
||||
|
||||
ApplicationContext context = WebTestUtils.createApplicationContext(SampleConfig.class);
|
||||
List<String> names = Arrays.asList(context.getBeanDefinitionNames());
|
||||
|
||||
assertThat(names).doesNotContain("jacksonGeoModule");
|
||||
@@ -173,18 +179,4 @@ public class EnableSpringDataWebSupportIntegrationTests {
|
||||
|
||||
Arrays.asList(resolverTypes).forEach(type -> assertThat(resolvers).hasAtLeastOneElementOfType(type));
|
||||
}
|
||||
|
||||
private static void hide(String module) throws Exception {
|
||||
|
||||
Field field = ReflectionUtils.findField(SpringDataWebConfigurationImportSelector.class, module);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, null, false);
|
||||
}
|
||||
|
||||
private static void reEnable(String module) {
|
||||
|
||||
Field field = ReflectionUtils.findField(SpringDataWebConfigurationImportSelector.class, module);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,17 @@ package org.springframework.data.web.config;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.classloadersupport.ClassLoaderConfiguration;
|
||||
import org.springframework.data.classloadersupport.ClassLoaderRule;
|
||||
import org.springframework.data.web.ProjectingJackson2HttpMessageConverter;
|
||||
import org.springframework.data.web.XmlBeamHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.instrument.classloading.ShadowingClassLoader;
|
||||
|
||||
/**
|
||||
* Integration test for {@link SpringDataWebConfiguration}.
|
||||
@@ -42,32 +39,37 @@ import org.springframework.instrument.classloading.ShadowingClassLoader;
|
||||
*/
|
||||
public class SpringDataWebConfigurationIntegrationTests {
|
||||
|
||||
@Rule public ClassLoaderRule classLoader = new ClassLoaderRule();
|
||||
|
||||
@Test // DATACMNS-987
|
||||
@ClassLoaderConfiguration(hidePackage = com.fasterxml.jackson.databind.ObjectMapper.class)
|
||||
public void shouldNotLoadJacksonConverterWhenJacksonNotPresent() {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
||||
createConfigWithClassLoaderExcluding("com.fasterxml.jackson").extendMessageConverters(converters);
|
||||
createConfigWithClassLoader().extendMessageConverters(converters);
|
||||
|
||||
assertThat(converters, not(hasItem(instanceWithClassName(ProjectingJackson2HttpMessageConverter.class))));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-987
|
||||
@ClassLoaderConfiguration(hidePackage = com.jayway.jsonpath.DocumentContext.class)
|
||||
public void shouldNotLoadJacksonConverterWhenJaywayNotPresent() {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
||||
createConfigWithClassLoaderExcluding("com.jayway").extendMessageConverters(converters);
|
||||
createConfigWithClassLoader().extendMessageConverters(converters);
|
||||
|
||||
assertThat(converters, not(hasItem(instanceWithClassName(ProjectingJackson2HttpMessageConverter.class))));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-987
|
||||
@ClassLoaderConfiguration(hidePackage = org.xmlbeam.ProjectionFactory.class)
|
||||
public void shouldNotLoadXBeamConverterWhenXBeamNotPresent() throws Exception {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
||||
createConfigWithClassLoaderExcluding("org.xmlbeam").extendMessageConverters(converters);
|
||||
createConfigWithClassLoader().extendMessageConverters(converters);
|
||||
|
||||
assertThat(converters, not(hasItem(instanceWithClassName(XmlBeamHttpMessageConverter.class))));
|
||||
}
|
||||
@@ -77,17 +79,17 @@ public class SpringDataWebConfigurationIntegrationTests {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
||||
createConfigWithClassLoaderExcluding("load.everything").extendMessageConverters(converters);
|
||||
createConfigWithClassLoader().extendMessageConverters(converters);
|
||||
|
||||
assertThat(converters, hasItem(instanceWithClassName(XmlBeamHttpMessageConverter.class)));
|
||||
assertThat(converters, hasItem(instanceWithClassName(ProjectingJackson2HttpMessageConverter.class)));
|
||||
}
|
||||
|
||||
private static SpringDataWebConfiguration createConfigWithClassLoaderExcluding(String excludedClassNamePrefix) {
|
||||
private SpringDataWebConfiguration createConfigWithClassLoader() {
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
SpringDataWebConfiguration.class);
|
||||
context.setClassLoader(initClassLoader(excludedClassNamePrefix));
|
||||
context.setClassLoader(classLoader.classLoader);
|
||||
|
||||
try {
|
||||
return context.getBean(SpringDataWebConfiguration.class);
|
||||
@@ -106,38 +108,4 @@ public class SpringDataWebConfigurationIntegrationTests {
|
||||
private static <T> Matcher<T> instanceWithClassName(Class<T> expectedClass) {
|
||||
return hasProperty("class", hasProperty("name", equalTo(expectedClass.getName())));
|
||||
}
|
||||
|
||||
private static ClassLoader initClassLoader(final String excludedClassNamePrefix) {
|
||||
|
||||
return new ShadowingClassLoader(URLClassLoader.getSystemClassLoader()) {
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
|
||||
if (name.startsWith(excludedClassNamePrefix)) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
|
||||
return super.loadClass(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
|
||||
if (name.startsWith(excludedClassNamePrefix)) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
|
||||
return super.findClass(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class ObjectFactoryImpl implements ObjectFactory<ConversionService> {
|
||||
|
||||
@Override
|
||||
public ConversionService getObject() throws BeansException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user