diff --git a/src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java b/src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java deleted file mode 100644 index 731487413..000000000 --- a/src/test/java/org/springframework/data/classloadersupport/ClassLoaderConfiguration.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1def36324..000000000 --- a/src/test/java/org/springframework/data/classloadersupport/ClassLoaderRule.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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 index 27e5ca46b..cfa2dddc0 100644 --- a/src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java +++ b/src/test/java/org/springframework/data/classloadersupport/HidingClassLoader.java @@ -16,29 +16,60 @@ package org.springframework.data.classloadersupport; import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.util.Assert; /** - * 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
  • - *
+ * 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 + * @author Oliver Gierke */ public class HidingClassLoader extends ShadowingClassLoader { private final Collection hidden; HidingClassLoader(Collection hidden) { + super(URLClassLoader.getSystemClassLoader()); + this.hidden = hidden; } + /** + * Creates a new {@link HidingClassLoader} with the packages of the given classes hidden. + * + * @param packages must not be {@literal null}. + * @return + */ + public static HidingClassLoader hide(Class... packages) { + + Assert.notNull(packages, "Packages must not be null!"); + + List result = new ArrayList(packages.length); + + for (Class type : packages) { + result.add(type.getPackage().getName()); + } + + return new HidingClassLoader(result); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.classloadersupport.ShadowingClassLoader#loadClass(java.lang.String) + */ @Override public Class loadClass(String name) throws ClassNotFoundException { @@ -46,6 +77,10 @@ public class HidingClassLoader extends ShadowingClassLoader { return super.loadClass(name); } + /* + * (non-Javadoc) + * @see java.lang.ClassLoader#findClass(java.lang.String) + */ @Override protected Class findClass(String name) throws ClassNotFoundException { diff --git a/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java b/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java index 6011f424b..0da59f9e7 100644 --- a/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java +++ b/src/test/java/org/springframework/data/classloadersupport/ShadowingClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-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. @@ -33,34 +33,31 @@ import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; /** - * ClassLoader decorator that shadows an enclosing ClassLoader, - * applying registered transformers to all affected classes. + * Copy of Spring Frameworks {@link org.springframework.instrument.classloading.ShadowingClassLoader} tweaked to not + * register default exclusions. ClassLoader decorator that shadows an enclosing ClassLoader, applying registered + * transformers to all affected classes. * * @author Rob Harrop * @author Juergen Hoeller * @author Costin Leau + * @author Jens Schauder + * @author Oliver Gierke * @since 2.0 * @see #addTransformer * @see org.springframework.core.OverridingClassLoader + * @see https://jira.spring.io/browse/SPR-15439 */ 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) { @@ -68,10 +65,9 @@ public class ShadowingClassLoader extends DecoratingClassLoader { this.enclosingClassLoader = enclosingClassLoader; } - /** - * Add the given ClassFileTransformer to the list of transformers that this - * ClassLoader will apply. + * Add the given ClassFileTransformer to the list of transformers that this ClassLoader will apply. + * * @param transformer the ClassFileTransformer */ public void addTransformer(ClassFileTransformer transformer) { @@ -80,8 +76,9 @@ public class ShadowingClassLoader extends DecoratingClassLoader { } /** - * Copy all ClassFileTransformers from the given ClassLoader to the list of - * transformers that this ClassLoader will apply. + * 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) { @@ -89,7 +86,6 @@ public class ShadowingClassLoader extends DecoratingClassLoader { this.classFileTransformers.addAll(other.classFileTransformers); } - @Override public Class loadClass(String name) throws ClassNotFoundException { if (shouldShadow(name)) { @@ -99,25 +95,25 @@ public class ShadowingClassLoader extends DecoratingClassLoader { return cls; } return doLoadClass(name); - } - else { + } 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)); + return (!className.equals(getClass().getName()) && !className.endsWith("ShadowingClassLoader") + && isEligibleForShadowing(className)); } /** - * Determine whether the specified class is eligible for shadowing - * by this class loader. + * 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 @@ -126,7 +122,6 @@ public class ShadowingClassLoader extends DecoratingClassLoader { return isExcluded(className); } - private Class doLoadClass(String name) throws ClassNotFoundException { String internalName = StringUtils.replace(name, ".", "/") + ".class"; InputStream is = this.enclosingClassLoader.getResourceAsStream(internalName); @@ -147,8 +142,7 @@ public class ShadowingClassLoader extends DecoratingClassLoader { } this.classCache.put(name, cls); return cls; - } - catch (IOException ex) { + } catch (IOException ex) { throw new ClassNotFoundException("Cannot load resource for class [" + name + "]", ex); } } @@ -161,13 +155,11 @@ public class ShadowingClassLoader extends DecoratingClassLoader { bytes = (transformed != null ? transformed : bytes); } return bytes; - } - catch (IllegalClassFormatException ex) { + } catch (IllegalClassFormatException ex) { throw new IllegalStateException(ex); } } - @Override public URL getResource(String name) { return this.enclosingClassLoader.getResource(name); @@ -182,5 +174,4 @@ public class ShadowingClassLoader extends DecoratingClassLoader { public Enumeration getResources(String name) throws IOException { return this.enclosingClassLoader.getResources(name); } - } 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 60e3e350f..54a5497df 100644 --- a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java @@ -25,14 +25,12 @@ import java.util.Arrays; import java.util.List; 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.classloadersupport.HidingClassLoader; import org.springframework.data.geo.Distance; import org.springframework.data.geo.Point; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; @@ -45,10 +43,11 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; 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; +import com.fasterxml.jackson.databind.ObjectMapper; + /** * Integration tests for {@link EnableSpringDataWebSupport}. * @@ -56,9 +55,6 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Jens Schauder * @see DATACMNS-330 */ - -@ClassLoaderConfiguration(shadowPackage = { WebMvcConfigurationSupport.class, EnableSpringDataWebSupport.class, - EnableSpringDataWebSupportIntegrationTests.SampleConfig.class }) public class EnableSpringDataWebSupportIntegrationTests { @Configuration @@ -71,8 +67,6 @@ public class EnableSpringDataWebSupportIntegrationTests { } } - @Rule public ClassLoaderRule classLoaderRule = new ClassLoaderRule(); - @Test public void registersBasicBeanDefinitions() throws Exception { @@ -96,10 +90,11 @@ public class EnableSpringDataWebSupportIntegrationTests { } @Test - @ClassLoaderConfiguration(hidePackage = Link.class) public void doesNotRegisterHateoasSpecificComponentsIfHateoasNotPresent() throws Exception { - ApplicationContext context = WebTestUtils.createApplicationContext(classLoaderRule.classLoader, SampleConfig.class); + HidingClassLoader classLoader = HidingClassLoader.hide(Link.class); + + ApplicationContext context = WebTestUtils.createApplicationContext(classLoader, SampleConfig.class); List names = Arrays.asList(context.getBeanDefinitionNames()); @@ -122,11 +117,10 @@ public class EnableSpringDataWebSupportIntegrationTests { /** * @see DATACMNS-475 */ - @Test - @ClassLoaderConfiguration(hidePackage = com.fasterxml.jackson.databind.ObjectMapper.class) public void doesNotRegisterJacksonSpecificComponentsIfJacksonNotPresent() throws Exception { - ApplicationContext context = WebTestUtils.createApplicationContext(classLoaderRule.classLoader, SampleConfig.class); + ApplicationContext context = WebTestUtils.createApplicationContext(HidingClassLoader.hide(ObjectMapper.class), + SampleConfig.class); List names = Arrays.asList(context.getBeanDefinitionNames());