43

Autowiring a non-primitive with spring annotations like bellow works:

@Autowired
lateinit var metaDataService: MetaDataService

But this doesn't work:

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

Error:

lateinit modifier is not allowed for primitive types.

How to autowire primitve properties into Kotlin classes?

ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
fkurth
  • 868
  • 1
  • 8
  • 11

7 Answers7

48

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.

anstue
  • 990
  • 12
  • 24
21

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

should be

@Value("\${cacheTimeSeconds}")
val cacheTimeSeconds: Int? = null
qwert_ukg
  • 490
  • 5
  • 15
  • also u can inject `env` and pass values form there, using `lazy` delegate – qwert_ukg Jun 07 '18 at 05:44
  • 2
    I would advise against a nullable type, if possible (and not only because OP said that's not an option). Making something nullable that you didn't intend to make nullable by design is basically going backwards towards Java... – milosmns Mar 10 '21 at 11:23
12

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
ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
drix
  • 177
  • 3
  • 9
3

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)
    }
}
Yao Yuan
  • 350
  • 3
  • 11
1

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

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62
  • 1
    OP says "Autowiring a non-primitive with spring annotations"... – powermilk Mar 08 '21 at 06:32
  • @powermilk Could you share the property to try to deduce why it fails or reproduce? And also the full error – Braian Coronel Mar 08 '21 at 12:36
  • 1
    String is Object, not primitive. I know, there is only objects in Kotlin, but not for JVM. See example in OP: `@Value("\${cacheTimeSeconds}") lateinit var cacheTimeSeconds: Int` There is few solutions are given in this thread, but without default value and outside constructor you can do it in this way: `@delegate:Value("\${cacheTimeSeconds}") var cacheTimeSeconds by Delegates.notNull()` – powermilk Mar 08 '21 at 13:10
  • Updated answer. Thanks – Braian Coronel Mar 08 '21 at 13:57
0

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.

Nuno André
  • 4,739
  • 1
  • 33
  • 46
jrtapsell
  • 6,719
  • 1
  • 26
  • 49
0

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.

Eduard Kornev
  • 554
  • 4
  • 21