Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent ALL of Jackson auto-config in Spring?

Context

I have a situation where I do not control the main of the application nor the libraries on the class path. I am extending (via a plug-in API) an existing Swing application. The goal of my project is to make the information inside of that legacy application available through a HTTP API to then interface it via a web application.

Technical situation

The application in question has already Jackson in the class path in version 2.7. I am trying to use Spring Boot version 2, which is built against Jackson 2.8. When I start the server, Spring is unable to initialise because it is trying to configure Jackson stuff, using classes and methods that did not exist in 2.7.

What I would like to do is prevent Spring from automatically configuring anything Jackson-related and let me provide my own content negotiator.

I already tried

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

but it does not work.

Digging into Spring code, I see places where it is hard-coded inside of AllEncompassingFormHttpMessageConverter that is Jackson is on the class path, it should create new objects (that cause the exception in question), despite the fact I am excluding the Jackson configuration in my Spring Boot application.

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());

and then later:

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

Project as it is now

Here is a link to GitHub, to the right branch.

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

The project in this state causes the error. Run ./gradlew server-standalone:run.

Complete error log

The errors I get are the following:

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 file

I was able to recreate the conditions of this situation with this Gradle build file.

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

}
like image 580
Adeynack Avatar asked Oct 24 '25 05:10

Adeynack


1 Answers

The not-found class which causes the exception is InvalidDefinitionException

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

I found out that InvalidDefinitionException class exists in Jackson since 2.9 as you can see here: InvalidDefinitionException

So I changed the jackson_version value to 2.9.2 (latest) in build.gradle and tried to run the project as you described and the project started to run with no exception.

Now to exclude Jackson you can still use this:

@SpringBootApplication(
    exclude = arrayOf(JacksonAutoConfiguration::class)
)
like image 180
er-han Avatar answered Oct 25 '25 20:10

er-han