【问题标题】:how to use spring annotations like @Autowired or @Value in kotlin for primitive types?如何在 kotlin 中将 @Autowired 或 @Value 等弹簧注释用于原始类型?
【发布时间】:2018-02-24 14:23:57
【问题描述】:

使用 spring 注释自动装配非基元,例如

@Autowired
lateinit var metaDataService: MetaDataService

有效。

但这不起作用:

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

出现错误:

原始类型不允许使用lateinit修饰符。

如何将原始属性自动装配到 kotlin 类中?

【问题讨论】:

  • 你能自动装配可空版本吗?该字段是否必须是lateinit
  • 是的,var todCacheTimeSeconds: Int? = null 有效,但这不是我想要的。

标签: spring kotlin kotlin-interop kotlin-null-safety


【解决方案1】:

没有默认值和外部构造函数

发件人:

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

收件人:

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

祝你好运

Kotlin doesn't have primitive type

【讨论】:

  • OP 说“使用弹簧注释自动装配非基元”...
  • @powermilk 您能否分享该属性以尝试推断其失败或重现的原因?还有完整的错误
  • 字符串是对象,不是原始的。我知道,Kotlin 中只有对象,但 JVM 中没有。请参阅 OP 中的示例:@Value("\${cacheTimeSeconds}") lateinit var cacheTimeSeconds: Int 此线程中给出的解决方案很少,但如果没有默认值和外部构造函数,您可以这样做:@delegate:Value("\${cacheTimeSeconds}") var cacheTimeSeconds by Delegates.notNull&lt;Int&gt;()
  • 更新了答案。谢谢
【解决方案2】:

你也可以在构造函数中使用@Value注解:

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

这样做的好处是您的变量是最终的且不可为空。我也更喜欢构造函数注入。它可以使测试更容易。

【讨论】:

    【解决方案3】:

    我只是像这样使用Number 而不是Int...

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

    其他选项是做其他人之前提到的......

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

    或者您可以简单地提供一个默认值,例如...

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

    在我的例子中,我必须得到一个 Boolean 类型的属性,这在 Kotlin 中是原始的,所以我的代码看起来像这样......

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

    【讨论】:

      【解决方案4】:

      尝试设置默认值

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

      在 application.properties 中

      a=1
      

      在代码中

      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)
          }
      }
      

      它将打印1

      或使用构造函数注入

      @Component
      class Main(@Value("\${a}") val a: Int) : CommandLineRunner {
      
          override fun run(vararg args: String) {
              println(a)
          }
      }
      

      【讨论】:

        【解决方案5】:

        问题不在于注解,而是原语和lateinit 的混合,根据this question,Kotlin 不允许lateinit 原语。

        解决方法是更改​​为可空类型Int?,或不使用lateinit

        This TryItOnline 显示问题。

        【讨论】:

          【解决方案6】:

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

          应该是

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

          【讨论】:

          • 你也可以注入env并在那里传递值,使用lazy委托
          • 如果可能的话,我建议不要使用可为空的类型(不仅因为 OP 说这不是一个选项)。使您不打算通过设计使其可以为空的东西可以为空基本上是在倒退到 Java...
          【解决方案7】:

          Kotlin 在 Java 代码中将 Int 编译为 int。 Spring 想要非原始类型进行注入,所以你应该使用 Int? /布尔? / 长?等。可空类型 kotlin 编译为 Integer / Boolean / etc.

          【讨论】:

            猜你喜欢
            • 2015-06-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-13
            • 1970-01-01
            相关资源
            最近更新 更多