语境

我遇到无法控制应用程序的main或类路径上的库的情况。我正在扩展(通过插件API)现有的Swing应用程序。我项目的目标是通过HTTP API使旧应用程序内部的信息可用,然后通过Web应用程序进行接口。

技术状况

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

我想做的是阻止Spring自动配置任何与Jackson相关的内容,并让我提供自己的内容协商者。

我已经试过了

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


但它不起作用。

深入研究Spring代码,我发现在AllEncompassingFormHttpMessageConverter内将其硬编码的位置放置在类路径上的Jackson上,尽管我排除了Jackson,但它应该创建新的对象(导致所讨论的异常)。我的Spring Boot应用程序中的配置。

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构建文件重新创建这种情况的条件。

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


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


我发现自2.9起,Jackson中存在InvalidDefinitionException类,如您在此处看到的:InvalidDefinitionException

因此,我将jackson_version中的2.9.2值更改为build.gradlelatest),并尝试按照您的描述运行该项目,并且该项目开始毫无例外地运行。

现在要排除Jackson,您仍然可以使用以下命令:

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

09-11 19:29
查看更多