将 kotlin 与项目反应堆一起使用时的平台类型和 jsr-305 注释

Platform types and jsr-305 annotations when using kotlin with project reactor

我正在使用带有 kotlin 的项目反应器。正如预期的那样,由于我正在编写调用 java 代码的 kotlin 代码,所以来自项目反应堆操作员的所有类型签名都显示为平台类型。例如

//here i is inferred as Int!
Mono.just(1).map { i -> i + 1 }

通读项目反应器的文档,似乎有一种方法可以断言所有类型都不可为空,并将这些类型推断为不可为空的类型。 https://projectreactor.io/docs/core/release/reference/#kotlin-null-safety

Kotlin support for JSR 305 annotations and Reactor nullability annotations provide null-safety for the whole Reactor API to Kotlin developers, with the advantage of dealing with null-related issues at compile time.

我曾尝试使用建议的编译器选项,但没有成功。使用以下 kotlin 配置,i 的类型仍然显示为 Int!,而我现在希望它是 Int.

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("jvm") version "1.6.10"
    application
}

group = "me.stef"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(kotlin("test"))
    implementation("io.projectreactor:reactor-core:3.4.14")
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        jvmTarget = "1.8"
        freeCompilerArgs = listOf("-Xjsr305=strict")
    }
}

application {
    mainClass.set("MainKt")
}

我正在使用带有 kotlin 插件版本 213-1.6.10-release-961-IJ6777.52

的 intelliJ IDEA Ultimate 版本 2021.3.2

我知道我可以使用显式类型注释将平台类型转换为可空或非空类型,但我希望尽可能避免这种情况。

所以我的问题是:

  1. 我是否正确地解释了文档以理解在将项目反应堆与 kotlin 一起使用时确实有一种方法可以强制执行不可为空的类型?
  2. 如果我理解正确,并且 jsr305 编译器选项是实现我的目标的方式,那么我做错了什么?
  3. 如果那不是实现我目标的方法,我该怎么做?
  4. 会不会是intellij的问题?

实际上该行为是设计使然,因为 @NonNullApi which is applied to a package from where you are calling the method (map) 没有使用默认限定符的类型,只有 METHODPARAMETER。特别是,这意味着 Kotlin 编译器不会增强类型参数位置内的类型,而只会增强 return 类型和值参数位置中的整个类型。

可以用下面的代码证明:

fun main() {
    // useless unsafe call before `get()` is reported because
    // the Kotlin compiler already enhanced the return type of `blockOptional` to not-null
    Mono.just(1).blockOptional()?.get()
}

在您的特定情况下,lambda 的值参数 i 映射到 map 声明中 FunctionT 类型参数,对应于 输入 use 位置。这就是 Kotlin 编译器不增强这种类型的原因。

请注意,Kotlin 编译器在类型使用位置默认情况下支持从 Java 增强类型。请参阅 following 编译器测试。

因此,为 reactor 创建一个功能请求以扩展其 NonNullApi 注释的范围以键入使用位置可能是有意义的。