From c20f18cc5d9adf4a0075fa941713707af95772ec Mon Sep 17 00:00:00 2001 From: Chris Povirk Date: Mon, 1 Nov 2021 12:23:45 -0400 Subject: [PATCH] Update code to prepare for nullness annotations in Guava. Guava's current nullness annotations don't yet trigger Kotlin compile errors. However, Guava did recently remove the misleading `@Nullable` annotation from the parameter of `FutureCallback.onSuccess`: Before: https://github.com/google/guava/blob/v28.0/guava/src/com/google/common/util/concurrent/FutureCallback.java#L34 After: https://github.com/google/guava/blob/v31.0.1/guava/src/com/google/common/util/concurrent/FutureCallback.java#L35 That means that a `FutureCallback` can now implement `onSuccess(T)` instead of `onSuccess(T?)`. And with a future change to Guava, it will _have to_. (For background, see the section on "Nullness annotations" in https://github.com/google/guava/releases/tag/v31.0) In order to make that change, this commit updates from from Guava 28.0 to Guava 31.0.1. When I performed that update, I found that that pulled in a newer version of the Checker Framework nullness annotations. That version was build with a newer version of Gradle, so it generates Gradle module metadata: https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html That metadata declares that the Checker Framework annotations require Java 1.8. Even the old version had in fact required Java 1.8 -- and so had even the old version of Guava -- just without having that encoded in its metadata. So I fixed this by setting targetCompatibility and sourceCompatibility to 1.8 for kotlinx-coroutines-guava, too. --- integration/kotlinx-coroutines-guava/README.md | 2 +- integration/kotlinx-coroutines-guava/build.gradle.kts | 7 ++++++- .../kotlinx-coroutines-guava/src/ListenableFuture.kt | 10 ++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/integration/kotlinx-coroutines-guava/README.md b/integration/kotlinx-coroutines-guava/README.md index 34b8e5818f..b930a6194c 100644 --- a/integration/kotlinx-coroutines-guava/README.md +++ b/integration/kotlinx-coroutines-guava/README.md @@ -62,6 +62,6 @@ Integration with Guava [ListenableFuture](https://github.com/google/guava/wiki/L -[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/https://google.github.io/guava/releases/28.0-jre/api/docs/com/google/common/util/concurrent/ListenableFuture.html +[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/https://google.github.io/guava/releases/31.0.1-jre/api/docs/com/google/common/util/concurrent/ListenableFuture.html diff --git a/integration/kotlinx-coroutines-guava/build.gradle.kts b/integration/kotlinx-coroutines-guava/build.gradle.kts index 12a6ca70b7..ebddd3c9ce 100644 --- a/integration/kotlinx-coroutines-guava/build.gradle.kts +++ b/integration/kotlinx-coroutines-guava/build.gradle.kts @@ -2,12 +2,17 @@ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ -val guavaVersion = "28.0-jre" +val guavaVersion = "31.0.1-jre" dependencies { compile("com.google.guava:guava:$guavaVersion") } +java { + targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 +} + externalDocumentationLink( url = "https://google.github.io/guava/releases/$guavaVersion/api/docs/" ) diff --git a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt index d214cc6b1a..0820f1f101 100644 --- a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt +++ b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt @@ -135,10 +135,8 @@ public fun ListenableFuture.asDeferred(): Deferred { // Finally, if this isn't done yet, attach a Listener that will complete the Deferred. val deferred = CompletableDeferred() Futures.addCallback(this, object : FutureCallback { - override fun onSuccess(result: T?) { - // Here we work with flexible types, so we unchecked cast to trick the type system - @Suppress("UNCHECKED_CAST") - runCatching { deferred.complete(result as T) } + override fun onSuccess(result: T) { + runCatching { deferred.complete(result) } .onFailure { handleCoroutineException(EmptyCoroutineContext, it) } } @@ -351,7 +349,7 @@ private class JobListenableFuture(private val jobToCancel: Job): ListenableFu * * To preserve Coroutine's [CancellationException], this future points to either `T` or [Cancelled]. */ - private val auxFuture = SettableFuture.create() + private val auxFuture = SettableFuture.create() /** * `true` if [auxFuture.get][ListenableFuture.get] throws [ExecutionException]. @@ -436,7 +434,7 @@ private class JobListenableFuture(private val jobToCancel: Job): ListenableFu } /** See [get()]. */ - private fun getInternal(result: Any): T = if (result is Cancelled) { + private fun getInternal(result: Any?): T = if (result is Cancelled) { throw CancellationException().initCause(result.exception) } else { // We know that `auxFuture` can contain either `T` or `Cancelled`.