From 8b6cc3af1179d8bf8b236944ea008a3afee75316 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 7 Sep 2018 11:58:58 +0200 Subject: [PATCH] DATACMNS-1386 - Avoid strong type dependency to Jackson in SpringDataWebConfiguration. We now avoid using a Lambda to provide a default ObjectMapper instance in the code that's reflectively guarded against Jackson not being present. The lambda causes a method to be generated for the class that will require ObjectMapper to be present on reflection inspection of that method. Switching to a method reference to ObjectMapper's constructor resolves that problem as the indirection via the additional, offending method is not needed. Further reading: https://www.javabullets.com/how-lambdas-and-anonymous-inner-classesaic-work/ --- .../config/SpringDataWebConfiguration.java | 2 +- ...gDataWebConfigurationIntegrationTests.java | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) 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 e015c8702..4276702cf 100644 --- a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java @@ -158,7 +158,7 @@ public class SpringDataWebConfiguration implements WebMvcConfigurer, BeanClassLo if (ClassUtils.isPresent("com.jayway.jsonpath.DocumentContext", context.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", context.getClassLoader())) { - ObjectMapper mapper = getUniqueBean(ObjectMapper.class, context, () -> new ObjectMapper()); + ObjectMapper mapper = getUniqueBean(ObjectMapper.class, context, ObjectMapper::new); ProjectingJackson2HttpMessageConverter converter = new ProjectingJackson2HttpMessageConverter(mapper); converter.setBeanFactory(context); 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 2e4dc1ce4..236f7b5a8 100644 --- a/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/SpringDataWebConfigurationIntegrationTests.java @@ -28,10 +28,12 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.classloadersupport.HidingClassLoader; +import org.springframework.data.classloadersupport.ShadowingClassLoader; import org.springframework.data.web.ProjectingJackson2HttpMessageConverter; import org.springframework.data.web.XmlBeamHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.util.ReflectionUtils; import org.xmlbeam.XBProjector; import com.fasterxml.jackson.databind.ObjectMapper; @@ -108,8 +110,13 @@ public class SpringDataWebConfigurationIntegrationTests { }, SomeConfiguration.class); } - private void createConfigWithClassLoader(ClassLoader classLoader, Consumer callback, - Class... additionalConfigurationClasses) { + @Test // DATACMNS-1386 + public void doesNotFailWithJacksonMissing() throws Exception { + ReflectionUtils.getUniqueDeclaredMethods(loadWithout(SpringDataWebConfiguration.class, ObjectMapper.class)); + } + + private static void createConfigWithClassLoader(ClassLoader classLoader, + Consumer callback, Class... additionalConfigurationClasses) { List> configClasses = new ArrayList<>(Arrays.asList(additionalConfigurationClasses)); configClasses.add(SpringDataWebConfiguration.class); @@ -122,6 +129,16 @@ public class SpringDataWebConfigurationIntegrationTests { } } + private static Class loadWithout(Class configurationClass, Class... typesOfPackagesToExclude) + throws ClassNotFoundException { + + HidingClassLoader hidingClassLoader = HidingClassLoader.hide(typesOfPackagesToExclude); + ShadowingClassLoader loader = new ShadowingClassLoader(hidingClassLoader); + loader.excludeClass(configurationClass.getName()); + + return loader.loadClass(configurationClass.getName()); + } + /** * Creates a {@link Condition} that checks 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