diff --git a/pom.xml b/pom.xml index 9792a3308..1db9b70eb 100644 --- a/pom.xml +++ b/pom.xml @@ -270,7 +270,7 @@ test-process - ${project.build.directory}/generated-sources/test-annotations + ${project.build.directory}/generated-test-sources/test-annotations com.querydsl.apt.QuerydslAnnotationProcessor diff --git a/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java b/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java index b5b8f9acf..d1c3fda1e 100644 --- a/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java +++ b/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java @@ -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 { List 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())); } diff --git a/src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java b/src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java new file mode 100644 index 000000000..731487413 --- /dev/null +++ b/src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java @@ -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 {}; +} diff --git a/src/test/java/org/springframework/data/classloadersupport/ClassLoaderRule.java b/src/test/java/org/springframework/data/classloadersupport/ClassLoaderRule.java new file mode 100644 index 000000000..1def36324 --- /dev/null +++ b/src/test/java/org/springframework/data/classloadersupport/ClassLoaderRule.java @@ -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 mergeHidden(CombinedClassLoaderConfiguration configuration) { + + List hidden = new ArrayList(); + + 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 shadowPackages = new ArrayList(); + final List shadowByPrefix = new ArrayList(); + final List hidePackages = new ArrayList(); + final List hideByPrefix = new ArrayList(); + + 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())); + } + } + } +} diff --git a/src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java b/src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java new file mode 100644 index 000000000..27e5ca46b --- /dev/null +++ b/src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java @@ -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: + *
    + *
  • shadowed: reloaded by this classloader no matter if they are loaded already by the SystemClassLoader
  • + *
  • 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}
  • + *
  • all other classes get loaded by the SystemClassLoader
  • + *
+ * + * @author Jens Schauder + */ +public class HidingClassLoader extends ShadowingClassLoader { + + private final Collection hidden; + + HidingClassLoader(Collection 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(); + } + } + } +} diff --git a/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java b/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java new file mode 100644 index 000000000..6011f424b --- /dev/null +++ b/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java @@ -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 classFileTransformers = new LinkedList(); + + private final Map> classCache = new HashMap>(); + + + /** + * 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 getResources(String name) throws IOException { + return this.enclosingClassLoader.getResources(name); + } + +} diff --git a/src/test/java/org/springframework/data/web/WebTestUtils.java b/src/test/java/org/springframework/data/web/WebTestUtils.java index 2c8c6a0df..58fcbef4d 100644 --- a/src/test/java/org/springframework/data/web/WebTestUtils.java +++ b/src/test/java/org/springframework/data/web/WebTestUtils.java @@ -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) { diff --git a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java index e78e736cb..13a2d0311 100755 --- a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java @@ -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 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 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); - } } diff --git a/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java b/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java index 06fb61432..32b5133ed 100644 --- a/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java @@ -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> converters = new ArrayList>(); - 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> converters = new ArrayList>(); - 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> converters = new ArrayList>(); - createConfigWithClassLoaderExcluding("org.xmlbeam").extendMessageConverters(converters); + createConfigWithClassLoader().extendMessageConverters(converters); assertThat(converters, not(hasItem(instanceWithClassName(XmlBeamHttpMessageConverter.class)))); } @@ -77,17 +79,17 @@ public class SpringDataWebConfigurationIntegrationTests { List> converters = new ArrayList>(); - 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 Matcher instanceWithClassName(Class 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 { - - @Override - public ConversionService getObject() throws BeansException { - return null; - } - } }