From 0ad1a8dad397e1fa5b8eb4cd8588a2633d3cd207 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Fri, 3 Feb 2017 11:51:24 +0100 Subject: [PATCH] DATACMNS-987 - Jackson converter gets only loaded if Jackson and Jayway dependencies are present. Added a test for loading of QuerydslPredicateArgumentResolver, but it fails presumably because EnableSpringDataWebSupport is not in effect. Renamed SpringDataWebConfigurationUnitTests to SpringDataWebConfigurationIntegrationTests since it is actually an integration test. Related ticket: DATACMNS-993. --- .../config/SpringDataWebConfiguration.java | 5 +- ...gDataWebConfigurationIntegrationTests.java | 200 ++++++++++++++++++ .../SpringDataWebConfigurationUnitTests.java | 102 --------- 3 files changed, 203 insertions(+), 104 deletions(-) create mode 100644 src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationUnitTests.java diff --git a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java index 9b6436292..4c3ab0566 100644 --- a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-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. @@ -118,7 +118,8 @@ public class SpringDataWebConfiguration extends WebMvcConfigurerAdapter { @Override public void extendMessageConverters(List> converters) { - if (ClassUtils.isPresent("com.jayway.jsonpath.DocumentContext", context.getClassLoader())) { + if (ClassUtils.isPresent("com.jayway.jsonpath.DocumentContext", context.getClassLoader()) + && ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", context.getClassLoader())) { ProjectingJackson2HttpMessageConverter converter = new ProjectingJackson2HttpMessageConverter(new ObjectMapper()); converter.setBeanClassLoader(context.getClassLoader()); diff --git a/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java b/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java new file mode 100644 index 000000000..56488c1d5 --- /dev/null +++ b/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java @@ -0,0 +1,200 @@ +/* + * Copyright 2015-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.web.config; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.springframework.test.util.ReflectionTestUtils.*; + +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import org.hamcrest.Matcher; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.convert.ConversionService; +import org.springframework.data.web.ProjectingJackson2HttpMessageConverter; +import org.springframework.data.web.XmlBeamHttpMessageConverter; +import org.springframework.data.web.querydsl.QuerydslPredicateArgumentResolver; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.instrument.classloading.ShadowingClassLoader; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; + +/** + * @author Christoph Strobl + * @author Jens Schauder + */ +public class SpringDataWebConfigurationIntegrationTests { + + @Test // DATACMNS-669 + public void shouldNotAddQuerydslPredicateArgumentResolverWhenQuerydslNotPresent() throws ClassNotFoundException, + InstantiationException, IllegalAccessException { + + ClassLoader classLoader = initClassLoader("com.mysema"); + + Object config = classLoader.loadClass(SpringDataWebConfiguration.class.getName()) + .newInstance(); + + setField(config, "context", classLoader.loadClass(GenericWebApplicationContext.class.getName()).newInstance() + ); + setField(config, "conversionService", classLoader.loadClass(ObjectFactoryImpl.class.getName()).newInstance()); + + List argumentResolvers = new ArrayList(); + + invokeMethod(config, "addArgumentResolvers", argumentResolvers); + + assertThat(argumentResolvers, + not(hasItem((Matcher) instanceWithClassName(QuerydslPredicateArgumentResolver.class)))); + } + + @Test // DATACMNS-669 + @Ignore("currently fails because he setup is not sufficient to trigger loading of the QuerydslArgumentResolver. See DATACMNS-993") + public void shouldAddQuerydslPredicateArgumentResolverWhenQuerydslPresent() throws ClassNotFoundException, + InstantiationException, IllegalAccessException { + + ClassLoader classLoader = initClassLoader("load.everything"); + + Object config = classLoader.loadClass(SpringDataWebConfiguration.class.getName()) + .newInstance(); + + setField(config, "context", classLoader.loadClass(GenericWebApplicationContext.class.getName()).newInstance()); + setField(config, "conversionService", classLoader.loadClass(ObjectFactoryImpl.class.getName()).newInstance()); + + List argumentResolvers = new ArrayList(); + + invokeMethod(config, "addArgumentResolvers", argumentResolvers); + + assertThat(argumentResolvers, + hasItem((Matcher) instanceWithClassName(QuerydslPredicateArgumentResolver.class))); + } + + @Test // DATACOMNS-987 + public void shouldNotLoadJacksonConverterWhenJacksonNotPresent() { + + SpringDataWebConfiguration config = createConfigWithClassLoaderExcluding("com.fasterxml.jackson"); + + List> converters = new ArrayList>(); + + config.extendMessageConverters(converters); + + assertThat(converters, (Matcher) not(hasItem( // + instanceWithClassName(ProjectingJackson2HttpMessageConverter.class)))); + } + + @Test // DATACOMNS-987 + public void shouldNotLoadJacksonConverterWhenJaywayNotPresent() { + + SpringDataWebConfiguration config = createConfigWithClassLoaderExcluding("com.jayway"); + + List> converters = new ArrayList>(); + + config.extendMessageConverters(converters); + + assertThat(converters, (Matcher) not(hasItem( // + instanceWithClassName(ProjectingJackson2HttpMessageConverter.class)))); + } + + @Test // DATACOMNS-987 + public void shouldNotLoadXBeamConverterWhenXBeamNotPresent() throws ClassNotFoundException, IllegalAccessException, InstantiationException { + + SpringDataWebConfiguration config = createConfigWithClassLoaderExcluding("org.xmlbeam"); + + List> converters = new ArrayList>(); + + config.extendMessageConverters(converters); + + assertThat(converters, (Matcher) not(hasItem( // + instanceWithClassName(XmlBeamHttpMessageConverter.class)))); + } + + + @Test // DATACOMNS-987 + public void shouldLoadAllConvertersWhenDependenciesArePresent() throws ClassNotFoundException, + IllegalAccessException, InstantiationException { + + SpringDataWebConfiguration config = createConfigWithClassLoaderExcluding("load.everything"); + + List> converters = new ArrayList>(); + + config.extendMessageConverters(converters); + + assertThat(converters, containsInAnyOrder( // + instanceWithClassName(XmlBeamHttpMessageConverter.class), // + instanceWithClassName(ProjectingJackson2HttpMessageConverter.class))); + } + + private SpringDataWebConfiguration createConfigWithClassLoaderExcluding(String excludedClassNamePrefix) { + ClassLoader classLoader = initClassLoader(excludedClassNamePrefix); + + SpringDataWebConfiguration config = new SpringDataWebConfiguration(); + GenericApplicationContext applicationContext = new GenericApplicationContext(); + applicationContext.setClassLoader(classLoader); + + setField(config, "context", applicationContext); + + return config; + } + + /** + * creates a Matcher that check if an object is an instance of a class with the same name as the provided class. + * This is necessary since we are dealing with multiple classloaders which would make a simple instanceof fail all + * the time + * + * @param expectedClass the class that is expected (possibly loaded by a different classloader). + * @return a Matcher + */ + private Matcher instanceWithClassName(Class expectedClass) { + return hasProperty("class", hasProperty("name", equalTo(expectedClass.getName()))); + } + + private 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; + } + } +} diff --git a/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationUnitTests.java b/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationUnitTests.java deleted file mode 100644 index 99e95e0b1..000000000 --- a/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationUnitTests.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2015-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.web.config; - -import static org.junit.Assert.*; -import static org.springframework.test.util.ReflectionTestUtils.*; - -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Test; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.core.convert.ConversionService; -import org.springframework.data.web.querydsl.QuerydslPredicateArgumentResolver; -import org.springframework.instrument.classloading.ShadowingClassLoader; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; - -/** - * @author Christoph Strobl - */ -public class SpringDataWebConfigurationUnitTests { - - @Test // DATACMNS-669 - public void shouldNotAddQuerydslPredicateArgumentResolverWhenQuerydslNotPresent() throws ClassNotFoundException, - InstantiationException, IllegalAccessException { - - ClassLoader classLoader = initClassLoader(); - - Object config = classLoader.loadClass("org.springframework.data.web.config.SpringDataWebConfiguration") - .newInstance(); - - setField(config, "context", - classLoader.loadClass("org.springframework.web.context.support.GenericWebApplicationContext").newInstance()); - setField( - config, - "conversionService", - classLoader.loadClass( - "org.springframework.data.web.config.SpringDataWebConfigurationUnitTests$ObjectFactoryImpl").newInstance()); - - List argumentResolvers = new ArrayList(); - - invokeMethod(config, "addArgumentResolvers", argumentResolvers); - - for (Object resolver : argumentResolvers) { - if (resolver instanceof QuerydslPredicateArgumentResolver) { - fail("QuerydslPredicateArgumentResolver should not be present when Querydsl not on path"); - } - } - } - - private ClassLoader initClassLoader() { - - ClassLoader classLoader = new ShadowingClassLoader(URLClassLoader.getSystemClassLoader()) { - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - - if (name.startsWith("com.mysema")) { - throw new ClassNotFoundException(); - } - - return super.loadClass(name); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - - if (name.startsWith("com.mysema")) { - throw new ClassNotFoundException(); - } - - return super.findClass(name); - } - }; - - return classLoader; - } - - public static class ObjectFactoryImpl implements ObjectFactory { - - @Override - public ConversionService getObject() throws BeansException { - return null; - } - - } -}