Factory method 'kafkaTemplate' threw exception; nested exception is java.lang.VerifyError: Bad return type

Viewed 2932

So I'm migrating a microservice from Spring Framework to Spring Boot 2.3.10.RELEASE. But when I tried to create an integration test and started it, an obscure error occurred:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.kafka.core.KafkaTemplate]: Factory method 'kafkaTemplate' threw exception; nested exception is java.lang.VerifyError: Bad return type
Exception Details:
  Location:
    com/fasterxml/jackson/databind/cfg/MapperBuilder.streamFactory()Lcom/fasterxml/jackson/core/TokenStreamFactory; @7: areturn
  Reason:
    Type 'com/fasterxml/jackson/core/JsonFactory' (current frame, stack[0]) is not assignable to 'com/fasterxml/jackson/core/TokenStreamFactory' (from method signature)
  Current Frame:
    bci: @7
    flags: { }
    locals: { 'com/fasterxml/jackson/databind/cfg/MapperBuilder' }
    stack: { 'com/fasterxml/jackson/core/JsonFactory' }
  Bytecode:
    0x0000000: 2ab4 0002 b600 08b0                    

    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652)
    ... 333 common frames omitted
Caused by: java.lang.VerifyError: Bad return type
Exception Details:
  Location:
    com/fasterxml/jackson/databind/cfg/MapperBuilder.streamFactory()Lcom/fasterxml/jackson/core/TokenStreamFactory; @7: areturn
  Reason:
    Type 'com/fasterxml/jackson/core/JsonFactory' (current frame, stack[0]) is not assignable to 'com/fasterxml/jackson/core/TokenStreamFactory' (from method signature)
  Current Frame:
    bci: @7
    flags: { }
    locals: { 'com/fasterxml/jackson/databind/cfg/MapperBuilder' }
    stack: { 'com/fasterxml/jackson/core/JsonFactory' }
  Bytecode:
    0x0000000: 2ab4 0002 b600 08b0                    

    at com.fasterxml.jackson.databind.json.JsonMapper.builder(JsonMapper.java:114)
    at org.springframework.kafka.support.JacksonUtils.enhancedObjectMapper(JacksonUtils.java:58)
    at org.springframework.kafka.support.JacksonUtils.enhancedObjectMapper(JacksonUtils.java:47)
    at org.springframework.kafka.support.DefaultKafkaHeaderMapper.<init>(DefaultKafkaHeaderMapper.java:112)
    at org.springframework.kafka.support.converter.MessagingMessageConverter.<init>(MessagingMessageConverter.java:67)
    at org.springframework.kafka.core.KafkaTemplate.<init>(KafkaTemplate.java:101)
    at org.springframework.kafka.core.KafkaTemplate.<init>(KafkaTemplate.java:150)
    at org.springframework.kafka.core.KafkaTemplate.<init>(KafkaTemplate.java:122)
    at com.gdn.x.cart.v2.rest.web.config.kafka.KafkaConfig.kafkaTemplate(KafkaConfig.java:88)
    at com.gdn.x.cart.v2.rest.web.config.kafka.KafkaConfig$$EnhancerBySpringCGLIB$$62380140.CGLIB$kafkaTemplate$0(<generated>)
    at com.gdn.x.cart.v2.rest.web.config.kafka.KafkaConfig$$EnhancerBySpringCGLIB$$62380140$$FastClassBySpringCGLIB$$f4054673.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.gdn.x.cart.v2.rest.web.config.kafka.KafkaConfig$$EnhancerBySpringCGLIB$$62380140.kafkaTemplate(<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:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 334 common frames omitted

Here is my KafkaConfiguration:

    @EnableKafka
    @Configuration
    public class KafkaConfig {
      // Some Properties & Consumer Configurations
    
      @Bean
      public Map<String, Object> producerConfigs() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBrokerList);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, KafkaProducerInterceptor.class.getName());
        return props;
      }
    
      @Bean
      public ProducerFactory<String, String> producerFactory() {
        return new DefaultKafkaProducerFactory<>(producerConfigs());
      }
    
      @Bean
      public KafkaTemplate<String, String> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
      }
    }

The service pom parent is inherited from spring-boot-starter-parent with version 2.3.10.RELEASE. The Jackson libraries versions are also inherited from that parent pom and I checked all Jackson versions are using 2.11.4, there are no conflicting dependencies. The KafkaTemplate instantiates normally when I ran the application. It only throws that error when I started the integration test. What did I miss? Is there a way to debug this?

Here's what I had tried and failed:

  • Clean .m2 directory
  • Declare jackson-databind version explicitly in parent POM
  • Change JUnit 4 to JUnit 5
  • Upgrade maven plugins to the latest
  • Lower the Spring Boot version by 1
4 Answers

I realized that when starting a single integration test multiple banners of spring boot are printed in the terminal which led to my suspicion that it started multiple times for a single test case. Then I realized I included spring-boot-starter in the dependency section of the parent POM and tried to remove it. It works fine after being removed. Though I still didn't know the root cause.

I'm guessing you have multiple Jackson dependencies on test classpath. It compiles, but fails in runtime.

In my case two/more jack deps were found. I've used old jar dependency with old jackson and spring inner jackson dep. So check your dependencies list, figure out old dependency, then remove or exclude it and run clean build.

I've just set priority on newest jack dep (ignore all versions older than selected one).

Exclude dep with maven

Exclude dep with gradle

Excluding all fasterxml from spring-boot-starter-web has helped to me:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.datatype</groupId>
                <artifactId>jackson-datatype-jdk8</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.datatype</groupId>
                <artifactId>jackson-datatype-jsr310</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.module</groupId>
                <artifactId>jackson-module-parameter-names</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

And when it should be deployed to jboss/wildfly, I find necessary to put file jboss-deployment-structure.xml in WEB-INF with excluded jackson modules:

 <jboss-deployment-structure>
  <deployment>
    <exclusions>
      <module name="com.fasterxml.jackson.core.jackson-core" />
      <module name="com.fasterxml.jackson.core.jackson-annotations" />
      <module name="com.fasterxml.jackson.core.jackson-databind" />
      <module name="com.fasterxml.jackson.datatype.jackson-datatype-jdk8" />
      <module name="com.fasterxml.jackson.datatype.jackson-datatype-jsr310" />
      <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider" />
      <module name="org.jboss.resteasy.resteasy-jackson2-provider" />
      <module name="org.jboss.resteasy.resteasy-jackson-provider" />
    </exclusions>
    ...
  </deployment>
</jboss-deployment-structure>
Related