How can I suppress unchecked cast warnings? - kotlin

Having the following code:
fun doSomething(): List<String> {
val test: List<*> = arrayListOf("test1", "test2")
return test as List<String>
}
Is there some way to suppress the unchecked cast warning that comes up in the last line? I tried to use the standard Java way #SuppressWarnings("unchecked") at the method level, but it didn't work.

Adding #Suppress("UNCHECKED_CAST") (also possible through IDEA's Alt+Enter menu) to any of statement, function, class and file should help.
Before:
After:

Related

Kotlin script - "extension method" is a member and an extension at the same time

I have Kotlin some code that works as a class but when I try and run it as a Kotlin script I am getting " error: 'getNameAndVersion' is a member and an extension at the same time. References to such elements are not allowed"
enum class Env { Test, Sit }
data class ImageVersions(val apiName: String, val versions: Map<Env, String?>)
fun String.getNameAndVersion() = substringBefore(':') to substringAfter(':')
val testList = listOf("api-car-v1:0.0.118", "api-dog-v1:0.0.11", "api-plane-v1:0.0.36")
val sitList = listOf("api-car-v1:0.0.119", "api-plane-v1:0.0.37", "api-dog-v1:0.0.12")
getVersions(
mapOf(
Env.Test to testList,
Env.Sit to sitList
)
).forEach(::println)
fun getVersions(envMap: Map<Env, List<String>>): List<ImageVersions> {
val envApiNameMap = envMap.mapValues { it.value.associate(String::getNameAndVersion) }
val allApiNames = envApiNameMap.flatMap { it.value.keys }.distinct()
return allApiNames.map { apiName ->
ImageVersions(apiName, envApiNameMap.mapValues { it.value[apiName] })
}
}
I don't think I'm doing anything wrong with the way I'm using the method reference but according to my compiler I'm wrong. Appreciate some help with this. thanks
kotlinc -script .\myscript.kts
error: 'getNameAndVersion' is a member and an extension at the same time. References to such elements are not allowed
I don't have any experience with scripts but this error occurs when you try to reference a function inside a class that is also an extension function. (Here it is pointing to String::getNameAndVersion). Maybe when you run a script, the entire code is wrapped inside a class and then executed.
To fix this you can do one of the following:
Convert the function to a normal function which accepts a String parameter.
fun getNameAndVersion(s: String) = s.substringBefore(':') to s.substringAfter(':')
And replace String::getNameAndVersion with just ::getNameAndVersion in associate function
Other option is to directly call the function in the associate's lambda instead of passing a reference of this function.
.associate { it.getNameAndVersion() }

Kotlin compiler not warning about potential null pointer exception

I have this simple kotlin snipped that tries to map list elements to strings like this:
sealed class MySealedClass
class MyClass1 : MySealedClass()
class MyClass2 : MySealedClass()
fun doTheMapThing(elements: List<MySealedClass>): List<String> {
return elements.flatMap {
when (it) {
is MyClass1 -> listOf("Yeah")
is MyClass2 -> null
}
}
}
In the flatMap, the when either maps to a list or to null, so the effective return type of the when is List<String>?. I was a bit surprised to see this compiling without any issues. Shouldn't the kotlin compiler warn about this? When I extract the when to a function, I get a proper compiler error. Am I missing something here or could this be a bug?
Using kotlin 1.5.31
Just for completeness: It was a bug. The fix will be released with Kotlin 1.7.0. More details on that can be found here: https://youtrack.jetbrains.com/issue/KT-49658
If you're interested in even more details, you can find the actual fix here: https://github.com/JetBrains/kotlin/commit/37d163d417bfe8ecd2e4baea3e5651906c96e150
A nice thing is that our example actually made it into the test code for kotlin:
fun doTheMapThing1(elements: List<CharSequence>): List<String> {
return elements.flatMap {
<!TYPE_MISMATCH_WARNING!>when (it) { // NullPointerException
is String -> listOf("Yeah")
else -> null
}<!>
}
}

How to cast generic type after isAssignableFrom check in Kotlin?

See the example:
class MyTypeAdapter<T : Throwable>
(private val gson: Gson, private val skipPast: TypeAdapterFactory) : TypeAdapter<T>() {
// :Throwable is needed to access the stackTrace field
}
private class ThrowableTypeAdapterFactory : TypeAdapterFactory {
override fun <T> create(gson: Gson, typeToken: TypeToken<T>): TypeAdapter<T>? {
if (Throwable::class.java.isAssignableFrom(typeToken.rawType)) {
return MyTypeAdapter<T>(gson, this) // compile error: Type argument is not within its bound
}
return null
}
}
So in Java we have raw use parameterized class but Kotlin doesn't allow it anymore.
I tried to find something from https://kotlinlang.org/docs/reference/generics.html
but couldn't get a clue. Please advice.
You should be able to cheat thanks to type erasure:
return MyTypeAdapter<Throwable>(gson, this) as MyTypeAdapter<T>
It looks wrong, but the class can't actually do anything different depending on T.
Or if Kotlin won't accept this cast directly (can't check at the moment) something like
return (MyTypeAdapter<Throwable>(gson, this) as MyTypeAdapter<*>) as MyTypeAdapter<T>
or even
return (MyTypeAdapter<Throwable>(gson, this) as Any) as MyTypeAdapter<T>
should work.

Suppressing warnings about an unused Kotlin property in IDEA

Consider I have a parameterized TestNG test:
val parameters: Array<Array<Any>>
#DataProvider
get() {
val parameters = arrayListOf<Array<Any>>()
// ...
return parameters.toTypedArray()
}
#Test(dataProvider = "getParameters")
fun test(p1: Any, pN: Any) {
// ...
}
How do I stop IDEA from complaining that the data provider property (parameters in our case) is unused? Annotating the property with #get:SuppressWarnings("unused") is not helpful.
Add this on top of the declaration of the parameters property: #Suppress("unused")
You might need to re-compile the project to get IntelliJ to stop highlighting it as an unused property.
There turned out to be a workaround. Rewriting the annotation like this:
#get:DataProvider
val parameters: Array<Array<Any>>
makes IDEA treat the property as an entry point.
The corresponding ticket is KT-28031.

How to cast Any to a List in Kotlin?

When I try to cast Any to a List like in the example below I get 'Unchecked cast: Any! to List' warning. Are there any workarounds to this kind of problem?
val x: List<Apples> = objectOfTypeAny as List<Apples>
This is "just" a warning saying that it's not 100% safe just to cast. The better option would be:
if (objectOfTypeAny is List<*>) {
val a: List<Apples> = objectOfTypeAny.filterIsInstance<Apples>()
...
}
See https://kotlinlang.org/docs/reference/typecasts.html for details.
Except ignoring the warning (or improving the design to avoid the cast), no.
This warning means that the cast can succeed at runtime even though the list is not actually a List<Apples>, but contains something other than Apples.
It exists because generics are not reified in Java. Generics work with type erasure. they're a compile-time safety net, not a runtime safety net.
Solution case for android Serializable to ArrayList:
ModJsonAndDb - your class
private fun serializableToArrayList(obj: Serializable?): ArrayList<ModJsonAndDb>? {
return if (obj is ArrayList<*>) {
ArrayList(obj.filterIsInstance<ModJsonAndDb>())
} else {
null
}
}
1. Add:
inline fun <reified T> List<*>.asListOfType(): List<T>? =
if (all { it is T })
#Suppress("UNCHECKED_CAST")
this as List<T> else
null
2. Use:
val list: List<YouType> = someAnyList?.asListOfType<YouType>()