codependent
codependent

Reputation: 24452

IntelliJ Idea 2017.3 unable to start Kotlin Spring Boot App - @Configuration class may not be final

I was able to launch a Spring Boot Kotlin App from IntelliJ 2017.3. After the last IntelliJ fix update I cannot start that application from the IDE, getting this exception:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'AccessConfig' may not be final

I can start it from a terminal as usual: java -jar xxxx.jar

This doesn't make any sense since I am using the necessary Kotlin Spring plugin in my Gradle config:

buildscript {
    ext {
        kotlinVersion = '1.2.21'
        springBootVersion = '2.0.0.RC1'
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
        jcenter()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
        classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3'
        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.2'
        classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.5"
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'maven'
...
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

repositories {
    mavenLocal()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
    maven { url "http://repo.maven.apache.org/maven2" }
    maven { url 'https://jitpack.io' }
}

ext {
    springCloudVersion = 'Finchley.M5'
    mmaReleaseTrainVersion = 'Callao-SNAPSHOT'
    junitVersion = '5.0.2'
}

Any ideas?

UPDATE:

A simpler way to reproduce, just create a Spring Boot project with the Spring initializer from IntelliJ, you'll see the same result:

DemoApplication:

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    SpringApplication.run(DemoApplication::class.java, *args)
}

Error:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'DemoApplication' may not be final. Remove the final modifier to continue.
Offending resource: com.example.demo.DemoApplication

build.gradle:

buildscript {
    ext {
        kotlinVersion = '1.2.10'
        springBootVersion = '1.5.10.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
    compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Upvotes: 19

Views: 16658

Answers (6)

midi
midi

Reputation: 4058

This solved it for me (just add the following line to plugins):

plugins {
id "org.jetbrains.kotlin.plugin.spring" version "1.5.10"
}

Or this approach:

buildscript {
dependencies {
    classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}

apply plugin: "kotlin-spring" 

Or in Maven:

<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>

<dependencies>
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-maven-allopen</artifactId>
    <version>${kotlin.version}</version>
</dependency>

For not Spring Applications do the following:

plugins {
  id "org.jetbrains.kotlin.plugin.allopen" version "1.5.10"
}

or this approach:

buildscript {
dependencies {
    classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}

apply plugin: "kotlin-allopen"

After that specify the list of annotations that will make classes open

allOpen {
annotation("com.my.Annotation")
}

Or work with meta-annotations:

@com.my.Annotation
annotation class MyFrameworkAnnotation

@MyFrameworkAnnotation
class MyClass //all-open

how to use all-open with Maven:

<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>

<configuration>
    <compilerPlugins>
        <plugin>all-open</plugin>
    </compilerPlugins>

    <pluginOptions>
        <option>all-open:annotation=com.my.Annotation</option>
        <option>all-open:annotation=com.their.AnotherAnnotation</option>
    </pluginOptions>
</configuration>

<dependencies>
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-maven-allopen</artifactId>
        <version>${kotlin.version}</version>
    </dependency>
</dependencies>

Upvotes: 1

abitcode
abitcode

Reputation: 1582

If you need to have open behavior default to all Spring related classes in kotlin, you can use kotlin-allopen plugin from here

https://search.maven.org/classic/#search%7Cga%7C1%7Ckotlin%20allopen

More info : https://www.baeldung.com/kotlin-allopen-spring

Upvotes: 1

Stanislav
Stanislav

Reputation: 28106

First of all, it's all due to class Kotlin class definition:

The open annotation on a class is the opposite of Java's final: it allows others to inherit from this class. By default, all classes in Kotlin are final

so if you are free to modify your source code, you can make your class not final, just adding open to it's signature as follows:

@SpringBootApplication
open class DemoApplication

fun main(args: Array<String>) {
    SpringApplication.run(DemoApplication::class.java, *args)
}

or one of the possible solutions, according to this article:

The @SpringBootApplication is a convenience annotation that marks the class with the @Configuration, @EnableAutoConfiguration and @ComponentScan annotations. It is the @Configuration annotation that forces the use of the open keyword.

Is to try to remove the @SpringBootApplication annotation and annotate your class with @EnableAutoConfiguration and @ComponentScan to solve this issue.

Upvotes: 31

BhathiyaW
BhathiyaW

Reputation: 356

If you get this error on IntelliJ, even with kotlin-spring plugin, you may want to check if the annotation processing has been enabled in IntelliJ.

Upvotes: 3

Teimuraz
Teimuraz

Reputation: 9325

If plugin update does not help, check if version of kotlin in gradle matches ide's kotlin version.

Upvotes: 2

codependent
codependent

Reputation: 24452

Fixed upgrading IntelliJ's Kotlin pluging to 1.2.21: https://plugins.jetbrains.com/plugin/6954-kotlin/update/42501

Upvotes: 5

Related Questions