I created a new project on Kotlin to generate a report. Knowing Kotlin can reduce number of lines of code and is safer than Java, I used Spring-jpa and Kotlin to get this done. All my @Configuration
classes had an error:
Classes annotated with @Configuration could be implicitly subclassed and must not be final
FYI, I am using a maven project with Kotlin 1.3.50. From my knowledge, I knew that spring does subclass for injecting values.
How do I make spring happy but not keep writing open in each of my class where spring complains?
A class annotated with @Configuration cannot be final because Spring will use CGLIB to create a proxy for @Configuration class. CGLIB creates subclass for each class that is supposed to be proxied, however since the final class cannot have subclass CGLIB will fail.
@Configuration is: not required, if you already pass the annotated class in the sources parameter when calling the SpringApplication. run() method; required, when you don't pass the annotated class explicitly, but it's in the package that's specified in the @ComponentScan annotation of your main configuration class.
final: default The final modifier mark classes and methods as not allowed to be overridden. In Kotlin this is the default. This decision was made to avoid fragile base class problem. It happens when a small change in base classes (super classes) make subclasses to malfunction.
Enabling @Autowired Annotations The Spring framework enables automatic dependency injection. In other words, by declaring all the bean dependencies in a Spring configuration file, Spring container can autowire relationships between collaborating beans. This is called Spring bean autowiring.
As you might already know, by default kotlin classes can not be extended. In order to support inheritance, you got to add open
keyword. Also, we know for a fact that spring annotation processing needs classes marked as @Configuration
can be subclassed.
The alternative of writing open in each of the classes is to add a plugin : kotlin-allopen
ex :
<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>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
The above does the trick of adding open to the following annotations: @Component
, @Async
, @Transactional
, @Cacheable
and @SpringBootTest
. Thanks to meta-annotations support classes annotated with @Configuration
, @Controller
, @RestController
, @Service
or @Repository
are automatically opened since these annotations are meta-annotated with @Component
.
You can find the documentation here: https://kotlinlang.org/docs/reference/compiler-plugins.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With