如何防止Spring中的所有Jackson自动配置?

时间:2017-11-30 16:21:10

标签: java spring spring-mvc spring-boot jackson2

上下文

我遇到的情况是我不控制应用程序的main和类路径上的库。我正在扩展(通过插件API)现有的Swing应用程序。我的项目的目标是通过HTTP API使该遗留应用程序内的信息可用,然后通过Web应用程序与其进行交互。

技术情况

相关应用程序已在版本2.7的类路径中 Jackson 。我正在尝试使用 Spring Boot 版本2,它是针对 Jackson 2.8构建的。当我启动服务器时, Spring 无法初始化,因为它正在尝试使用2.7中不存在的类和方法来配置 Jackson 。 / p>

我想要做的是阻止 Spring 自动配置任何与 Jackson 相关的内容,让我提供自己的内容协商员。< / p>

我已经尝试了

@SpringBootApplication(
    exclude = arrayOf(JacksonAutoConfiguration::class)
)

但它不起作用。

深入研究 Spring 代码,我发现AllEncompassingFormHttpMessageConverter里面的 Jackson 是硬编码的地方,它应该在类路径上创建尽管我在 Spring Boot 应用程序中排除了 Jackson 配置,但新对象(导致有问题的异常)仍然存在。

private static final boolean jackson2Present =
        ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader()) &&
                ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", AllEncompassingFormHttpMessageConverter.class.getClassLoader());

然后再说:

    if (jackson2Present) {
        addPartConverter(new MappingJackson2HttpMessageConverter());
    }

项目现在是

这是指向右侧分支的GitHub链接。

https://github.com/Adeynack/finances/tree/spring--jackson-init-bypass/backend

处于此状态的项目会导致错误。运行./gradlew server-standalone:run

完整的错误日志

我得到的错误如下:

2017-11-30 17:15:54,475 | ERROR | main                                 | o.springframework.boot.SpringApplication | Application startup failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:137)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:122)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1245)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
    at com.github.adeynack.finances.backend.serverStandalone.FinancesServerStandalone.main(FinancesServerStandalone.kt:10)
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:114)
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:81)
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:527)
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:185)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:161)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:134)
    ... 8 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'httpPutFormContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter]: Factory method 'httpPutFormContentFilter' threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:583)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1249)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1098)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$83/517355658.getObject(Unknown Source)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:228)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:182)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:177)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAdaptableBeans(ServletContextInitializerBeans.java:159)
    at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:80)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:232)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:219)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext$$Lambda$126/1009916891.onStartup(Unknown Source)
    at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:54)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter]: Factory method 'httpPutFormContentFilter' threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:186)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:575)
    ... 26 common frames omitted
Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
    at org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter.<init>(AllEncompassingFormHttpMessageConverter.java:67)
    at org.springframework.web.filter.HttpPutFormContentFilter.<init>(HttpPutFormContentFilter.java:63)
    at org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter.<init>(OrderedHttpPutFormContentFilter.java:29)
    at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.httpPutFormContentFilter(WebMvcAutoConfiguration.java:161)
    at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$$EnhancerBySpringCGLIB$$f9ae12ce.CGLIB$httpPutFormContentFilter$1(<generated>)
    at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$$EnhancerBySpringCGLIB$$f9ae12ce$$FastClassBySpringCGLIB$$60a40e61.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
    at org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$$EnhancerBySpringCGLIB$$f9ae12ce.httpPutFormContentFilter(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:155)
    ... 27 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 41 common frames omitted

Gradle文件

我能够使用此Gradle构建文件重新创建此情况的条件。

buildscript {

    ext {
        kotlin_version = '1.1.51'
        spring_boot_version = '2.0.0.M5'
        junit_version = '5.0.1'
        jackson_version = '2.7.9' // has to match Moneydance included Jackson version
    }

    repositories {
        mavenCentral()
        jcenter()
        maven { url 'https://repo.spring.io/libs-milestone' } // remove when using a stable version of Spring Boot 2.x
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.1'
        classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version"
    }
}

subprojects {

    apply plugin: 'java'
    apply plugin: 'kotlin'
    apply plugin: 'idea'
    apply plugin: 'org.junit.platform.gradle.plugin'
//    apply plugin: 'org.springframework.boot' // causes problems with Spring Boot 2. Unable to compile sub-projects.
    apply plugin: 'io.spring.dependency-management'

    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8

    repositories {
        mavenCentral()
        jcenter()
        maven { url 'https://repo.spring.io/libs-milestone' }
    }

    dependencies {

        //
        // PRODUCTION
        //

        // Kotlin and language extensions
        compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
        compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

        // Spring
        compile("org.springframework.boot:spring-boot-starter-web:$spring_boot_version") {
            // Totally excluding Jackson (version conflict between version included in Moneydance and the one used in SpringBoot
            exclude group: 'com.fasterxml.jackson.core'
            exclude group: 'com.fasterxml.jackson.datatype'
            exclude group: 'com.fasterxml.jackson.module'
        }

        compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version"

        //
        // TEST
        //

        // JUnit
        testCompile("org.junit.jupiter:junit-jupiter-api:$junit_version")
        testRuntime("org.junit.jupiter:junit-jupiter-engine:$junit_version")

    }

    compileKotlin {
        kotlinOptions {
            jvmTarget = JavaVersion.VERSION_1_8
        }
    }

    compileTestKotlin {
        kotlinOptions {
            jvmTarget = JavaVersion.VERSION_1_8
        }
    }

    junitPlatform {
        platformVersion '1.0.0'
    }

}

1 个答案:

答案 0 :(得分:1)

导致异常的未找到的类是InvalidDefinitionException

  

嵌套异常是java.lang.NoClassDefFoundError:com / fasterxml / jackson / databind / exc / InvalidDefinitionException

我发现自2.9以来杰克逊存在InvalidDefinitionException类,你可以在这里看到:InvalidDefinitionException

所以我在jackson_version中将2.9.2值更改为build.gradlelatest)并尝试按照您的描述运行项目,项目开始运行,没有例外

现在要排除Jackson,您仍然可以使用此功能:

@SpringBootApplication(
    exclude = arrayOf(JacksonAutoConfiguration::class)
)