Browse Source

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.
pull/18/merge
Jens Schauder 9 years ago committed by Oliver Gierke
parent
commit
65734739bd
  1. 2
      pom.xml
  2. 20
      src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java
  3. 60
      src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java
  4. 113
      src/test/java/org/springframework/data/classloadersupport/ClassLoaderRule.java
  5. 64
      src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java
  6. 186
      src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java
  7. 19
      src/test/java/org/springframework/data/web/WebTestUtils.java
  8. 54
      src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java
  9. 60
      src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java

2
pom.xml

@ -270,7 +270,7 @@ @@ -270,7 +270,7 @@
<goal>test-process</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources/test-annotations</outputDirectory>
<outputDirectory>${project.build.directory}/generated-test-sources/test-annotations</outputDirectory>
<processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor>
</configuration>
</execution>

20
src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java

@ -78,15 +78,22 @@ public @interface EnableSpringDataWebSupport { @@ -78,15 +78,22 @@ public @interface EnableSpringDataWebSupport {
* https://jira.springsource.org/browse/SPR-10565).
*
* @author Oliver Gierke
* @author Jens Schauder
*/
static class SpringDataWebConfigurationImportSelector implements ImportSelector, ResourceLoaderAware {
// Don't make final to allow test cases faking this to false
private static boolean HATEOAS_PRESENT = ClassUtils.isPresent("org.springframework.hateoas.Link", null);
private static boolean JACKSON_PRESENT = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null);
private Environment environment;
private ResourceLoader resourceLoader;
/*
* (non-Javadoc)
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.springframework.core.env.Environment)
*/
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org.springframework.core.io.ResourceLoader)
@ -105,10 +112,11 @@ public @interface EnableSpringDataWebSupport { @@ -105,10 +112,11 @@ public @interface EnableSpringDataWebSupport {
List<String> imports = new ArrayList<>();
imports.add(HATEOAS_PRESENT ? HateoasAwareSpringDataWebConfiguration.class.getName()
imports.add(ClassUtils.isPresent("org.springframework.hateoas.Link", resourceLoader.getClassLoader())
? HateoasAwareSpringDataWebConfiguration.class.getName()
: SpringDataWebConfiguration.class.getName());
if (JACKSON_PRESENT) {
if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", resourceLoader.getClassLoader())) {
imports.addAll(
SpringFactoriesLoader.loadFactoryNames(SpringDataJacksonModules.class, resourceLoader.getClassLoader()));
}

60
src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
/*
* Copyright 2017 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.data.classloadersupport;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* configures the {@link ClassLoaderRule}.
*
* @author Jens Schauder
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassLoaderConfiguration {
/**
* classes of which the package that contains them will be loaded by the {@link HidingClassLoader} not by
* the normal {@code ClassLoader}.
*
* @return list of classes not to shadow.
*/
Class[] shadowPackage() default {};
/**
* prefixes of class names that will be loaded by the {@link HidingClassLoader}.
*
* @return list of class prefixes which will not be shadowed.
*/
String[] shadowByPrefix() default {};
/**
* classes of which the package that contains them will be hidden by the {@link HidingClassLoader}.
*
* @return list of classes to hidePackage.
*/
Class[] hidePackage() default {};
/**
* classes from packages that will be hidden by the {@link HidingClassLoader}.
*
* @return list of classes of which the package will be hidden.
*/
String[] hideByPrefix() default {};
}

113
src/test/java/org/springframework/data/classloadersupport/ClassLoaderRule.java

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
/*
* Copyright 2017 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.data.classloadersupport;
import static java.util.Arrays.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
/**
* supports creation of tests that need to load classes with a {@link HidingClassLoader}.
*
* @author Jens Schauder
*/
public class ClassLoaderRule implements MethodRule {
public HidingClassLoader classLoader;
@Override
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
CombinedClassLoaderConfiguration combinedConfiguration = new CombinedClassLoaderConfiguration(
method.getAnnotation(ClassLoaderConfiguration.class),
method.getDeclaringClass().getAnnotation(ClassLoaderConfiguration.class)
);
classLoader = createClassLoader(combinedConfiguration);
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} finally {
classLoader = null;
}
}
};
}
private static HidingClassLoader createClassLoader(CombinedClassLoaderConfiguration configuration) {
HidingClassLoader classLoader = new HidingClassLoader(mergeHidden(configuration));
for (Class shadow : configuration.shadowPackages) {
classLoader.excludeClass(shadow.getPackage().getName());
}
for (String shadow : configuration.shadowByPrefix) {
classLoader.excludePackage(shadow);
}
return classLoader;
}
private static List<String> mergeHidden(CombinedClassLoaderConfiguration configuration) {
List<String> hidden = new ArrayList<String>();
for (Class aClass : configuration.hidePackages) {
hidden.add(aClass.getPackage().getName());
}
for (String aPackage : configuration.hideByPrefix) {
hidden.add(aPackage);
}
return hidden;
}
private static class CombinedClassLoaderConfiguration {
final List<Class> shadowPackages = new ArrayList<Class>();
final List<String> shadowByPrefix = new ArrayList<String>();
final List<Class> hidePackages = new ArrayList<Class>();
final List<String> hideByPrefix = new ArrayList<String>();
CombinedClassLoaderConfiguration(ClassLoaderConfiguration methodAnnotation, ClassLoaderConfiguration classAnnotation) {
mergeAnnotation(methodAnnotation);
mergeAnnotation(classAnnotation);
}
private void mergeAnnotation(ClassLoaderConfiguration methodAnnotation) {
if (methodAnnotation != null) {
shadowPackages.addAll(asList(methodAnnotation.shadowPackage()));
shadowByPrefix.addAll(asList(methodAnnotation.shadowByPrefix()));
hidePackages.addAll(asList(methodAnnotation.hidePackage()));
hideByPrefix.addAll(asList(methodAnnotation.hideByPrefix()));
}
}
}
}

64
src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
/*
* Copyright 2017 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.data.classloadersupport;
import java.net.URLClassLoader;
import java.util.Collection;
/**
* is intended for testing code that depends on the presence/absence of certain classes.
*
* Classes can be:
* <ul>
* <li>shadowed: reloaded by this classloader no matter if they are loaded already by the SystemClassLoader</li>
* <li>hidden: not loaded by this classloader no matter if they are loaded already by the SystemClassLoader. Trying to load these classes results in a {@link ClassNotFoundException}</li>
* <li>all other classes get loaded by the SystemClassLoader</li>
* </ul>
*
* @author Jens Schauder
*/
public class HidingClassLoader extends ShadowingClassLoader {
private final Collection<String> hidden;
HidingClassLoader(Collection<String> hidden) {
super(URLClassLoader.getSystemClassLoader());
this.hidden = hidden;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
checkIfHidden(name);
return super.loadClass(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
checkIfHidden(name);
return super.findClass(name);
}
private void checkIfHidden(String name) throws ClassNotFoundException {
for (String prefix : hidden) {
if (name.startsWith(prefix)) {
throw new ClassNotFoundException();
}
}
}
}

186
src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java

@ -0,0 +1,186 @@ @@ -0,0 +1,186 @@
/*
* 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.data.classloadersupport;
import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
/**
* ClassLoader decorator that shadows an enclosing ClassLoader,
* applying registered transformers to all affected classes.
*
* @author Rob Harrop
* @author Juergen Hoeller
* @author Costin Leau
* @since 2.0
* @see #addTransformer
* @see org.springframework.core.OverridingClassLoader
*/
public class ShadowingClassLoader extends DecoratingClassLoader {
/** Packages that are excluded by default */
public static final String[] DEFAULT_EXCLUDED_PACKAGES =
new String[] {"java.", "javax.", "sun.", "oracle.", "com.sun.", "com.ibm.", "COM.ibm.",
"org.w3c.", "org.xml.", "org.dom4j.", "org.eclipse", "org.aspectj.", "net.sf.cglib",
"org.springframework.cglib", "org.apache.xerces.", "org.apache.commons.logging."};
private final ClassLoader enclosingClassLoader;
private final List<ClassFileTransformer> classFileTransformers = new LinkedList<ClassFileTransformer>();
private final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
/**
* Create a new ShadowingClassLoader, decorating the given ClassLoader.
* @param enclosingClassLoader the ClassLoader to decorate
*/
public ShadowingClassLoader(ClassLoader enclosingClassLoader) {
Assert.notNull(enclosingClassLoader, "Enclosing ClassLoader must not be null");
this.enclosingClassLoader = enclosingClassLoader;
}
/**
* Add the given ClassFileTransformer to the list of transformers that this
* ClassLoader will apply.
* @param transformer the ClassFileTransformer
*/
public void addTransformer(ClassFileTransformer transformer) {
Assert.notNull(transformer, "Transformer must not be null");
this.classFileTransformers.add(transformer);
}
/**
* Copy all ClassFileTransformers from the given ClassLoader to the list of
* transformers that this ClassLoader will apply.
* @param other the ClassLoader to copy from
*/
public void copyTransformers(ShadowingClassLoader other) {
Assert.notNull(other, "Other ClassLoader must not be null");
this.classFileTransformers.addAll(other.classFileTransformers);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (shouldShadow(name)) {
System.out.println("shadowing " + name);
Class<?> cls = this.classCache.get(name);
if (cls != null) {
return cls;
}
return doLoadClass(name);
}
else {
return this.enclosingClassLoader.loadClass(name);
}
}
/**
* Determine whether the given class should be excluded from shadowing.
* @param className the name of the class
* @return whether the specified class should be shadowed
*/
private boolean shouldShadow(String className) {
return (!className.equals(getClass().getName()) && !className.endsWith("ShadowingClassLoader") &&
isEligibleForShadowing(className));
}
/**
* Determine whether the specified class is eligible for shadowing
* by this class loader.
* @param className the class name to check
* @return whether the specified class is eligible
* @see #isExcluded
*/
protected boolean isEligibleForShadowing(String className) {
return isExcluded(className);
}
private Class<?> doLoadClass(String name) throws ClassNotFoundException {
String internalName = StringUtils.replace(name, ".", "/") + ".class";
InputStream is = this.enclosingClassLoader.getResourceAsStream(internalName);
if (is == null) {
throw new ClassNotFoundException(name);
}
try {
byte[] bytes = FileCopyUtils.copyToByteArray(is);
bytes = applyTransformers(name, bytes);
Class<?> cls = defineClass(name, bytes, 0, bytes.length);
// Additional check for defining the package, if not defined yet.
if (cls.getPackage() == null) {
int packageSeparator = name.lastIndexOf('.');
if (packageSeparator != -1) {
String packageName = name.substring(0, packageSeparator);
definePackage(packageName, null, null, null, null, null, null, null);
}
}
this.classCache.put(name, cls);
return cls;
}
catch (IOException ex) {
throw new ClassNotFoundException("Cannot load resource for class [" + name + "]", ex);
}
}
private byte[] applyTransformers(String name, byte[] bytes) {
String internalName = StringUtils.replace(name, ".", "/");
try {
for (ClassFileTransformer transformer : this.classFileTransformers) {
byte[] transformed = transformer.transform(this, internalName, null, null, bytes);
bytes = (transformed != null ? transformed : bytes);
}
return bytes;
}
catch (IllegalClassFormatException ex) {
throw new IllegalStateException(ex);
}
}
@Override
public URL getResource(String name) {
return this.enclosingClassLoader.getResource(name);
}
@Override
public InputStream getResourceAsStream(String name) {
return this.enclosingClassLoader.getResourceAsStream(name);
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
return this.enclosingClassLoader.getResources(name);
}
}

19
src/test/java/org/springframework/data/web/WebTestUtils.java

@ -24,7 +24,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon @@ -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 { @@ -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) {

54
src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java

@ -20,56 +20,62 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder @@ -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 { @@ -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 { @@ -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 { @@ -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);
}
}

60
src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java

@ -18,20 +18,17 @@ package org.springframework.data.web.config; @@ -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; @@ -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 { @@ -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 { @@ -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;
}
}
}

Loading…
Cancel
Save