28
votes

Autowiring a non-primitive with spring annotations like

@Autowired
lateinit var metaDataService: MetaDataService

works.

But this doesn't work:

@Value("\${cacheTimeSeconds}")
lateinit var cacheTimeSeconds: Int

with an error:

lateinit modifier is not allowed for primitive types.

How to autowire primitve properties into kotlin classes?

7
Can you autowire the nullable version? And does the field have to be lateinit - jrtapsell
Yes, var todCacheTimeSeconds: Int? = null works, but thats not what i want. - fkurth

7 Answers

25
votes

You can also use the @Value annotation within the constructor:

class Test(
    @Value("\${my.value}")
    private val myValue: Long
) {
        //...
  }

This has the benefit that your variable is final and none-nullable. I also prefer constructor injection. It can make testing easier.

15
votes

@Value("\${cacheTimeSeconds}") lateinit var cacheTimeSeconds: Int

should be

@Value("\${cacheTimeSeconds}")
val cacheTimeSeconds: Int? = null
7
votes

I just used Number instead of Int like so...

    @Value("\${cacheTimeSeconds}")
    lateinit var cacheTimeSeconds: Number

The other options are to do what others mentioned before...

    @Value("\${cacheTimeSeconds}")
    var cacheTimeSeconds: Int? = null

Or you can simply provide a default value like...

    @Value("\${cacheTimeSeconds}")
    var cacheTimeSeconds: Int = 1

In my case I had to get a property that was a Boolean type which is primitive in Kotlin, so my code looks like this...

    @Value("\${myBoolProperty}")
    var myBoolProperty: Boolean = false
2
votes

Try to set a default value

    @Value("\${a}")
    val a: Int = 0

in application.properties

a=1

in the code

package com.example.demo

import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.stereotype.Component

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

@Component
class Main : CommandLineRunner {

    @Value("\${a}")
    val a: Int = 0

    override fun run(vararg args: String) {
        println(a)
    }
}

it will print 1

or use contructor inject

@Component
class Main(@Value("\${a}") val a: Int) : CommandLineRunner {

    override fun run(vararg args: String) {
        println(a)
    }
}
0
votes

Kotlin compiles Int to int in java code. Spring wanted non-primitive types for injection, so you should use Int? / Boolean? / Long? and etc. Nullable types kotlin compile to Integer / Boolean / etc.

0
votes

The problem is not the annotation, but the mix of primitive and lateinit, as per this question, Kotlin does not allow lateinit primitives.

The fix would be to change to a nullable type Int?, or to not use lateinit.

This TryItOnline shows the issue.

0
votes

Without default value and outside constructor

From:

@Value("\${cacheTimeSeconds}") lateinit var cacheTimeSeconds: Int

To:

@delegate:Value("\${cacheTimeSeconds}")  var cacheTimeSeconds by Delegates.notNull<Int>()

Good Luck

Kotlin doesn't have primitive type