Search code examples
javaspring-bootapache-kafkaspring-kafkaautowired

Can't find KafkaTemplate bean, even though I've defined one


My environment context looks like this:

- Spring Boot v2.5.12
- Maven Multi Module project (this is a module, it imports its Spring Boot dependencies from the parent pom)
- JDK 11

And the error that I am receiving looks like this:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 1 of constructor in com.example.group.service.SomeServiceImpl required a bean of type 'org.springframework.kafka.core.KafkaTemplate' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.kafka.core.KafkaTemplate' in your configuration.

The relevant files:

<!-- ${base.dir}/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>master-config</artifactId>
        <version>1.1.2</version>
    </parent>

    <groupId>com.example.group</groupId>
    <artifactId>parent-pom</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>app1</module>
        <module>app2</module>
    </modules>

    <properties>
        <java.version>11</java.version>
        <maven.compiler.release>${java.version}</maven.compiler.release>
        <spring.boot.version>2.5.12</spring.boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Omitted -->
        </dependencies>
    </dependencyManagement>
</project>

<!-- ${base.dir}/app2/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example.group</groupId>
        <artifactId>parent-pom</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>app2</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
// ${base.dir}/app2/src/main/java/com/example/group/SomeApplication.java

package com.example.group;

/* Imports omitted */

@SpringBootApplication
public class SomeApplication {
    public static void main(String[] args) {
        SpringApplication.run(SomeApplication.class, args);
    }
}

// ${base.dir}/app2/src/main/java/com/example/group/configuration/AppConfig.java
package com.example.group.configuration;

/* Imports omitted */

@Configuration
public class AppConfig {

    @Bean
    public KafkaTemplate<Bytes, Object> kafkaTemplate(ProducerFactory<Bytes, Object> kafkaProducerFactory) {
        return new KafkaTemplate<>(kafkaProducerFactory);
    }

    @Bean
    public ProducerFactory<Bytes, Object> kafkaProducerFactory() {
        Map<String, Object> producerProperties = /* Config omitted */;
        return new DefaultKafkaProducerFactory<>(producerProperties);
    }
}

// ${base.dir}/app2/src/main/java/com/example/group/service/SomeService.java
package com.example.group.service;

/* Imports omitted */

@Service
public final class SomeServiceImpl implements SomeService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SomeServiceImpl.class);

    private final KafkaTemplate<Bytes, Object> kafkaTemplate;
    private final String topic;

    @Autowired
    public SomeServiceImpl(
        KafkaTemplate<Bytes, Object> kafkaTemplate,
        @Value("${topic}") String topic) {
        this.kafkaTemplate = kafkaTemplate;
        this.topic = topic;
    }

    /* omitted */
}

This is bizarre and I cannot figure out why Spring keeps telling me it cannot find a KafkaTemplate bean. Even IntelliJ tells me that it cannot find an autowire candidate for KafkaTemplate.

Things I've tried

  1. Deleting my custom @Beans, and relying on KafkaAutoConfiguration (it fails, saying it cannot find a ProducerFactory)
  2. Giving the KafkaTemplate bean a name, and using @Qualifier in SomeService
  3. Moving the @Bean definitions around.

None of these have worked, and so I'm at my wits end. Any insights would be helpful.


Solution

  • So it turns out this was a case of PEBKAC (Problem exists between keyboard and chair).

    The Bytes type in my config object referred to com.google.common.primitives.Bytes and the Bytes in my service class referred to org.apache.kafka.common.utils.Bytes.

    Lesson to self:

    Check your types.