
Fixing Spring Configuration Issues in Kotlin: The Final Class Problem
Learn how to fix the 'Classes annotated with @Configuration must not be final' error in Kotlin Spring Boot applications using kotlin-allopen plugin. Complete guide with Maven & Gradle examples.
If you're working with Spring Boot and Kotlin, you might encounter this error when creating @Configuration
classes:
Classes annotated with @Configuration could be implicitly subclassed and must not be final
This article will explain why this happens and show you how to fix it properly in both Maven and Gradle projects.
Understanding the Problem
Why Does This Happen?
The issue stems from a fundamental difference between Kotlin and Java:
- In Kotlin, all classes are
final
by default (cannot be inherited) - Spring Framework needs to create proxy classes by subclassing certain Spring-annotated classes
- This creates a conflict when Spring tries to subclass your Kotlin classes
This particularly affects classes with these annotations:
@Configuration
@Component
@Service
@Repository
@Controller
- And others...
Solutions
Solution 1: Adding the 'open' Keyword (Not Recommended)
You could manually add the open
keyword to each class:
@Configuration
open class MyConfiguration {
// Configuration code
}
However, this approach:
- Is tedious
- Prone to errors
- Requires manual maintenance
- Not scalable for larger projects
Solution 2: Using the kotlin-allopen Plugin (Recommended)
A better solution is to use the kotlin-allopen
plugin, which automatically makes classes with specific annotations open.
For Maven Projects:
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
For Gradle Projects (build.gradle.kts):
plugins {
id("org.jetbrains.kotlin.plugin.spring") version "2.1.0"
}
What Does the Plugin Do?
The kotlin-allopen
plugin with the Spring preset automatically makes classes open when they have these annotations:
@Component
@Async
@Transactional
@Cacheable
@SpringBootTest
Additionally, thanks to meta-annotations, classes with these annotations are also automatically opened:
@Configuration
@Controller
@RestController
@Service
@Repository
Best Practices
- Always use the
kotlin-allopen
plugin in Spring Boot projects with Kotlin - Keep your build configuration up to date with the latest Kotlin version
- Understand which classes need to be open and why
- Use Spring Boot's starter for Kotlin when available
Common Issues and Solutions
Issue 1: Plugin Not Working
- Verify plugin version matches your Kotlin version
- Ensure proper plugin configuration in build file
- Check if annotations are imported correctly
Issue 2: Mixed Java/Kotlin Projects
- Configure source directories correctly
- Use consistent plugin versions
- Consider gradual migration strategies
Conclusion
The kotlin-allopen
plugin is the recommended way to handle Spring's proxy requirements in Kotlin projects. It provides an elegant solution that maintains Kotlin's safety features while working seamlessly with Spring's proxy-based features.