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

标签 java spring spring-mvc spring-boot jackson2

上下文

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

技术情况

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

我想做的是防止Spring自动配置任何Jackson相关的东西,让我提供我自己的内容谈判器。

我已经试过了

@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'
    }

}

最佳答案

导致异常的未找到类是InvalidDefinitionException

nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException

我发现 InvalidDefinitionException 类自 2.9 以来就存在于 Jackson 中,您可以在此处看到:InvalidDefinitionException

所以我在 build.gradle 中将 jackson_version 值更改为 2.9.2 ( latest ) 并尝试运行该项目您的描述和项目开始运行,无一异常(exception)。

现在排除 Jackson 你仍然可以使用这个:

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

关于java - 如何防止 Spring 中所有的 Jackson 自动配置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47577983/

相关文章:

java - Spring security REST api 自定义HTTP基本身份验证

java - 发送信息至电子邮件

java - 在 Java 8+ 中对 map 进行分区

java - Spring hibernate : reload entity mappings

java - 使用 spring mvc 和 jackson 允许带或不带根节点的 json 的正确方法

Spring Boot 响应已提交资源请求异常

java - 从 Powershell 运行 Java Jar

spring - 在同一台机器上运行两个独立的 HornetQ 服务器

java - 加载正确的 AWS 凭证时,您提供的 AWS 访问 key ID 不存在于我们的记录中

java - 可以替代 if 语句的设计模式