Why calling method toString() on function reference results in an error KotlinReflectionInternalError
fun main() {
fun foo(){}
::foo.toString()
}
output:
Exception in thread "main" kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Function 'foo' (JVM signature: main$foo()V) not resolved in class kotlin.jvm.internal.Intrinsics$Kotlin: no members found
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findFunctionDescriptor(KDeclarationContainerImpl.kt:131)
at kotlin.reflect.jvm.internal.KFunctionImpl$descriptor$2.invoke(KFunctionImpl.kt:56)
at kotlin.reflect.jvm.internal.KFunctionImpl$descriptor$2.invoke(KFunctionImpl.kt:55)
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:93)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32)
at kotlin.reflect.jvm.internal.KFunctionImpl.getDescriptor(KFunctionImpl.kt:55)
at kotlin.reflect.jvm.internal.KFunctionImpl.toString(KFunctionImpl.kt:185)
at kotlin.jvm.internal.FunctionReference.toString(FunctionReference.java:130)
at MainKt.main(Main.kt:3)
at MainKt.main(Main.kt)
Related
A quick demo of a problem:
import kotlin.reflect.jvm.kotlinFunction
interface A<T> {
fun aaa(t: T): String {
return ""
}
}
class B : A<String>
fun main() {
println(B::class.java.methods[0].kotlinFunction) // returns null
}
Calling kotlinFunction on a method without type parameter returns an instance of KFunction as expected.
The reason is type erasure, that occurs in Java, but not in Kotlin:
Java:
public java.lang.String B.aaa(java.lang.Object)
Kotlin:
public java.lang.String B.aaa(java.lang.String)
https://github.com/JetBrains/kotlin/blob/master/core/reflection.jvm/src/kotlin/reflect/jvm/ReflectJvmMapping.kt#L134
Note that it's just Kotlin compiler preserving some more information for reflection, types will be still erased by JVM at runtime, Kotlin or not.
If you need to access Kotlin method, do it directly:
println(B::class.functions.first())
Mirgating from Java to Kotlin I try to use static function with Data Binding:
<data>
<import type="com.package.domain.tools.helper.StringValidator"/>
...
</data>
Then I call function hideNumber:
<com.hastee.pay.ui.view.Text
...
android:text='#{StringValidator.hideNumber(account.number)}'
app:layout_constraintRight_toRightOf="#+id/number"
app:layout_constraintTop_toBottomOf="#+id/number" />
Using databinding here causes error:
[kapt] An exception occurred:
android.databinding.tool.util.LoggedErrorException: Found data binding
errors.
****/ data binding error ****msg:cannot find method
hideNumber(java.lang.String) in class
com.package.domain.tools.helper.StringValidator....
Here's this object:
object StringValidator {
...
fun hideNumber(number: String): String {
return "****" + number.substring(number.length - 4)
}
}
How can I reach this function using Kotlin and Data Binding?
The data binding compiler is looking for a static method.
Since a named object alone is not enough to make all methods inside that object static, you need an additional #JvmStatic annotation on your hideNumber-method:
#JvmStatic
fun hideNumber(number: String): String {
return "****" + number.substring(number.length - 4)
}
see also: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods
Today I ran into a really strange runtime error while developing kotlin / android that involves SAM conversions and sub classing.
Here's a minimal example of pure java + kotlin. Here are two java classes:
public class A {
public interface I {
public void f();
}
public I i;
}
public class B extends A {}
And here is a kotlin main function:
fun main(args: Array<String>) {
A().i = B.I {}
}
This code compiles fine but at run time I get the following error:
Exception in thread "main" java.lang.NoSuchMethodError: B.I(Lkotlin/jvm/functions/Function0;)LA$I;
at MainKt.main(Main.kt:2)
Now, this is already bad -- if code like this does not work (it never will I guess) the compiler should raise an error. But at least one could say that it is bad idea to reference to the interface I via the subclass B instead of the place of definition A (i.e., A.I).
It's less clear though, if this code is in a sub class of B where I can reference I directly using I:
class C: B {
constructor() {
this.i = I {}
}
}
So my questions would be:
Why is this behavior happening at all?
If it is happening, why is the compiler not raising an error already?
PS: In android the error message looks similar to this, which is even more confusing:
Caused by: java.lang.NoSuchMethodError: No static method OnFocusChangeListener(Lkotlin/jvm/functions/Function2;)Landroid/view/View$OnFocusChangeListener; in class Landroid/widget/LinearLayout; or its super classes (declaration of 'android.widget.LinearLayout' appears in /system/framework/framework.jar:classes2.dex)
Define main method as static like-
companion object {
#JvmStatic fun main(args: Array<String>) {
A().i = B.I {}
}
}
Kotin documentation says that "All exception classes in Kotlin are descendants of the class Throwable. Every exception has a message, stack trace and an optional cause."
The Java documentation for Throwable shows a getMessage() method. But the Kotlin documentation for Throwable does not have a getMessage(). So this code:
fun main(args: Array<String>)
{
try
{
println("args size: ${args.size}");
}
catch (e: Exception)
{
println(e.getMessage())
System.exit(1)
}
}
gives me this compile error:
test_exception.kt:12:17: error: unresolved reference: getMessage
println(e.getMessage())
^
suggesting that I am using a Kotlin Exception class derived from a Kotlin Throwable class.
However, if I change getMessage() to toString() and add a throw:
fun main(args: Array<String>)
{
try
{
println("args size: ${args.size}");
throw Exception("something went wrong")
}
catch (e: Exception)
{
println(e.toString())
System.exit(1)
}
}
I get this message:
java.lang.Exception: something went wrong
Which seems to say that the Exception class is NOT a Kotlin Exception class - but the java version which has a getMessage() method and I shouldn't get a compile error when I try to use it.
There is no other Throwable except for java.lang.Throwable. This class is used both by Java and by Kotlin programs.
The fact that Throwable has an entry in the Kotlin documentation suggests that this is a special compiler "alias". That means that for all intents and purposes it is a Kotlin class, instances of which are represented by java.lang.Throwable. Black magic.
TL;DR:
The equivalent of e.getMessage() in Kotlin is e.message, which is described in the docs as open val message: String?.
Since Throwable is not used directly from Java, but mapped to Kotlin, you cannot use the Java notation e.getMessage() for the property. Here is more about mapped types: http://kotlinlang.org/docs/reference/java-interop.html#mapped-types
Im trying to create a GsonRequest class that extends a normal volley request, and also implements the error listener. The code I'm using to do this is
public class GsonRequest<T>(url: String, val clazz: Class<T>) :
Request<T>(Request.Method.GET, url, this), ErrorListener
However, I'm getting the following error: 'this' is not defined in this context. Is what I'm trying to do possible?
You can not use this on the JVM before the super-constructor finished working, so you can not pass it to the super-constructor.
What you can do is use an object expression or a lambda for an error listener:
public class GsonRequest<T>(url: String, val clazz: Class<T>) :
Request<T>(Request.Method.GET, url, { <handling code here> } )
Alternatively, consider taking the listener as a parameter for constructor of class GsonRequest