Interoperability java-kotlin Nullable string crashing at runtime but why? - kotlin

I have an alternative to my problem, but I still have 2 questions:
Why it's crashing
Why Intellij/compiler is not complaining
I provided a small example of my issue. Here is an overview (you can find the code just after)
Car.java is the java class with a simple getter annoted as nulllable
MyView.kt is the crashing at runtime example with no warning in Intellij or in gradle. (Crashing when the value is null)
MyView2.kt is not crashing at runtime (even if mType is null)
Library.kt (kotlin stdlib) is simply the expected call for the example (even if it's weird to see string.toString())
Car.java
#Nullable
private String mType;
#Nullable
public String getCarType() {
return mType;
}
MyView.kt (crashing)
val test: String = myCar.carType.toString()
MyView2.kt (not crashing)
val carType: String? = myCar.carType
val test2: String = carType.toString()
Library.kt (kotlin stdlib)
/**
* Returns a string representation of the object. Can be called with a null receiver, in which case
* it returns the string "null".
*/
public fun Any?.toString(): String
Thanks! I guess this is a corner case of the interop between kotlin and java? Or... someone is aware of a better explanation?

The clue to this difference is the optional marker ? in this line in MyView2.kt
val carType: String? = myCar.carType
- here you are declaring to the Kotlin compiler that you know that carType is nullable. (In turn the behaviour of .toString() will work even though it is called on a null object, as you showed from the docs.)
However things are different in MyView.kt because the code doesn't get as far as the .toString() call. Here you are directly using a platform type (i.e. Java) where null-safety rules cannot be deduced.
This documentation about Calling Java code from Kotlin explains:
Types of Java declarations are treated in Kotlin in a specific manner and called platform types. Null-checks are relaxed for such types, so that safety guarantees for them are the same as in Java

Related

How can I tell the Kotlin compiler that a Java method will never return null?

I don't or can't modify the Java source code. The goal to configure just the Kotlin compiler to know what is nullable and what isn't.
You can specify the type manually if you know something will never be null. For example, if you have the following Java code:
public static Foo test() {
return null;
}
and you call it in Kotlin like this:
val result = Foo.test()
then result will have a type of Foo! by default – which means it can be either Foo or Foo?.. the compiler doesn't have enough information to determine that.
However, you can force the type manually:
val result: Foo = Foo.test()
// use "result" as a non-nullable type
Of course, if at runtime that is not true, you'll get a NullPointerException.
For reference, please check the documentation.
I don't know of a way to configure the compiler for this, but IntelliJ IDEA has a feature that allows you to add annotations to code via an XML file called external annotations.
You can add the Jetbrains #Nullable and #NotNull annotations to library code, but when I've tried it, it only results in compiler warnings rather than errors when you use incorrect nullability in your code. These same annotations generate compiler errors when used directly in the source code. I don't know why there is a difference in behavior.
You can use extension functions for this. If you have a method String foo() in the class Test, you can define the extension function
fun Test.safeFoo(): String = this.foo()!!
The advantage is that the code is pretty obious.
The disadvantage of this approach is that you need to write a lot of boiler plate code. You also have to define the extension function in a place where all your modules or projects can see it. Also, writing that much code just to avoid !! feels like overkill.
It should also be possible to write a Kotlin compiler extension which generates them for you but the extension would need to know which methods never return null.

Does the jar library built from Kotlin code still have all the feature like accessing local Kotlin code

I am looking at this https://docs.gradle.org/current/samples/sample_building_kotlin_libraries.html
to build a Kotlin jar library. But I am wondering -- if consumer code of the library is also using Kotlin, can it have all the benefits like accessing to local Kotlin code? For example:
Nullability check
Suspend keyword restriction
Named parameters
...
I figured out the answer is YES as long as the jar is built with source files.
suspend
The suspend keyword changes the descriptor of the functions to have an interface, Continuation<ReturnType> at the end of the parameter list. So if you have
suspend fun foo(i: Int, l: Long): String in kotlin, it gets compiled and decompiled to Java:
public final Object foo(int i, long l, Continuation<? super String> $completion). This is why some libraries had Java friendly functions that wraps suspend function call in runBlocking.
Null Checks
This works across languages, when kotlin compiles a function or expression call that specifies a non-null value, it adds null checks to the code. For example:
fun bar(s1: String, s2: String) adds these check in the method body:
Intrinsics.checkParameterIsNotNull((Object)s1, "s1");
Intrinsics.checkParameterIsNotNull((Object)s2, "s2");
And throws an exception when it is null.

how to convert Java Map to read it in Kotlin?

I am facing some very basic problem (that never faced in java before) and might be due my lack of knowledge in Kotlin.
I am currently trying to read a YML file. So Im doing it in this way:
private val factory = YamlConfigurationFactory(LinkedHashMap::class.java, validator, objectMapper, "dw")
Best on Dropwizard guide for configurations.
https://www.dropwizard.io/1.3.12/docs/manual/testing.html
So later in my function I do this"
val yml = File(Paths.get("config.yml").toUri())
var keyValues = factory.build(yml)
When using my debugger I can see there is a Map with key->values, just as it should be.
now when I do keyValues.get("my-key")
type inference failed. the value of the type parameter k should be mentioned in input types
Tried this but no luck
var keyValues = LinkedHashMap<String, Any>()
keyValues = factory.build(yml)
The YamlConfigurationFactory requires a class to map to, but I dont know if there is a more direct way to specify a Kotlin class than with the current solution +.kotlin, like
LinkedHashMap::class.java.kotlin
Here it also throws an error.
Ideas?
Well, this is a typical problem with JVM generics. Class<LinkedHashMap> carries no info on what are the actual types of its keys and values, so the keyValues variable always ends up with the type LinkedHashMap<*, *> simply because it can't be checked at compile time. There are two ways around this:
Unsafe Cast
This is how you would deal with the problem in standard Java: just cast the LinkedHashMap<*, *> to LinkedHashMap<String, Any> (or whatever is the actual expected type). This produces a warning because the compiler can't verify the cast is safe, but it is also generally known such situations are often unavoidable when dealing with JVM generics and serialisation.
YamlConfigurationFactory(LinkedHashMap::class.java, ...) as LinkedHashMap<String, Any>
Type Inference Magic
When using Kotlin, you can avoid the cast by actually creating instance of Class<LinkedHashMap<String, Any>> explicitly. Of course, since this is still JVM, you lose all the type info at runtime, but it should be enough to tell the type inference engine what your result should be. However, you'll need a special helper method for this (or at least I haven't found a simpler solution yet), but that method needs to be declared just once somewhere in your project:
inline fun <reified T> classOf(): Class<T> = T::class.java
...
val factory = YamlConfigurationFactory(classOf<LinkedHashMap<String, Any>>(), ...)
Using this "hack", you'll get an instance of LinkedHashMap directly, however, always remember that this is just extra info for the type inference engine but effectively it just hides the unsafe cast. Also, you can't use this if the type is not known at compile type (reified).

Is there a better way to write CompletableFutrue.XXXasync() invocations in kotlin?

Java CompletableFuture<T> has a lot of async methods, static or instance, in this format
public <U> CompletableFuture<U> XXXasync(SomeFunctionalInterface<T> something, Executor executor)
If you have enough experience with FP in kotlin, you will immediately realize these function are extremely awkward to use in kotlin, because the SAM interface is not the last parameter.
aCompletableFutrue.thenComposeAsync(Function<SomeType, CompletableFuture<SomeOtherType>> {
// ^ WHAT A LONG TYPE NAME THAT NEED TO BE HAND WRITTEN
// do something that has to be written in multiple lines.
// for that sake of simplicity I use convert() to represent this process
convert(it)
}, executor)
That Function has a very very long generic signature that I don't know how to let IDE generate. It will be a plain in the butt if the type name become even longer or contains a ParameterizedType or has type variance annotations.
It also looks nasty because of the trailing , executor) on line 5.
Is there some missing functionality in kotlin or IDE that can help with the situation? At least I don't want to write that long SAM constructor all by myself.
Rejected solutions:
Using named parameter doesn't seem to work because this feature only works on a kotlin function.
Abandon async methods sounds bad from the very beginning.
Kotlin corountine is rejected because we are working with some silly Java libraries that accept CompletionStage only.
IF you calling the api from java that takes a functional interface parameter at last, you can just using lambda in kotlin.
val composed: CompletableFuture<String> = aCompletableFutrue.thenComposeAsync {
CompletableFuture.supplyAsync { it.toString() }
};
Secondly, if you don't like the java api method signature. you can write your own extension methods, for example:
fun <T, U> CompletableFuture<T>.thenComposeAsync(executor: Executor
, mapping: Function1<in T, out CompletionStage<U>>): CompletableFuture<U> {
return thenComposeAsync(Function<T,CompletionStage<U>>{mapping(it)}, executor)
}
THEN you can makes the lambda along the method.
aCompletableFutrue.thenComposeAsync(executor){
// do working
}

Why is casting the type still necessary even though it has already been assured in this example?

Today I came across this section in the Kotlin Docs. Called "smart casts", Kotlin seems to "insert (safe) casts automatically when needed":
In many cases, one does not need to use explicit cast operators in
Kotlin, because the compiler tracks the is-checks for immutable values
and inserts (safe) casts automatically when needed:
fun demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
I don't understand what "smart casting" does in this example. There seems to be nothing that requires casting, as x will always be String and thus x.length will always work, no casting required. What is happening on the print line exactly? Thanks in advance!
x has a type Any, and that type doesn't have a .length property. However, since inside the if block, it's known that x is actually a String, it gets smart cast that type, and you can call methods and access properties of the String class on it.
The Java version of this code would look like this, you'd need an explicit cast to String even after doing the type check:
void demo(Object x) {
if(x instanceof String) {
System.out.print(((String) x).length());
}
}
This is what Kotlin simplifies for you.
Without smart casting, you would have to tell the compiler the type is actually a String, since length does not exist on Any.
println((x as String).length)
With smart casting this isn't necessary anymore.