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 {}
}
}
Related
I'm trying to migrate test framework from JUnit 5 to kotest.
I selected Annotation Spec at first (to check compatibility), but Nested Annotation doesn't work as expected
Sample code is below
class Outside : AnnotationSpec() {
#Test
fun runOutside() { }
#Nested
inner class Inside() {
#Test
fun runInside() { }
}
}
runOutside runs well, but runInside doesn't. The error message is java.lang.IllegalArgumentException: object is not an instance of declaring class
What's wrong ? is this a bug ?
I am new to kotlin and I am trying to use main function together with a class.
fun main() {
var demo = Person("Hello", 10)
println(demo)
}
private class Person (name: String, age: Int){
var name: String
var age: Int
init {
this.name = name
this.age = age
}
}
Although I have declared the main function, the compiler is still looking for the static main method in the class that I have defined, Person, and I got this error:
Error: Main method not found in class Person, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
What have I missed?
java Person is the problem, you are specifically telling it to look for the static void main method there. Top-level functions from Person.kt will be compiled into a PersonKt class by default and so you should run java PersonKt.
Also, the unnamed package you get by not specifying any package is weird in some ways, so I would recommend adding a package declaration from the start (and running java your.package.PersonKt).
I had the following problem and was able to resolve the problem by renaming the functions. I am finding myself struggling doing that without my workaround...
How is the following implementation possible without modifying the interfaces:
interface A {
fun test() { }
}
interface B {
suspend fun test()
}
class C : A, B {
suspend fun test(){ // Change that line as you wish
// Implementation
}
Notes: I know of the Kotlin Wiki. But this is more difficult as IntelliJ didn't show that C is a valid implementation of A.
(My problem as far as I know is that one of the interface defines a suspend function and the other does not. My gut feeling is that a non-suspending function should be ok with being implemented as a suspending function, but there does not seem to be such a relation)
Thanks for helping out!
How to force immediate instantiation of enum values?
By default, in Kotlin enums are instantiated on first access (like objects/singletons), i.e., the following minimal example
class Foo
fun create(msg: String) = Foo().also { println("$msg") }
enum class A(val foo: Foo) {
ONE(create("1")),
TWO(create("2"))
}
enum class B(val foo: Foo) {
THREE(create("3")),
FOUR(create("4"))
}
fun main() {
println("main")
println(A.ONE)
}
outputs:
main
1
2
ONE
Is it possible to force the enums to be instantiated directly/statically before main, such that the output is as follows?
1
2
3
4
main
ONE
Sure, I could just put something like val ignore = listOf(A.ONE, B.THREE) somewhere, but I'd like to avoid such manual repetition.
Maybe there's a way using some existing annotation, or creating a new one, or something else? :)
JVM loads classes only on first access. This is not only for kotlin but also for Java. For Java we have ways to initialize a class before main, for instance, static initializer block, or Class.forName. Similarly you can use the static initializer block in Kotlin.
object Temp {
init {
A.ONE
}
#JvmStatic fun main(args: Array<String>) {
println("main")
println(A.ONE)
}
}
I’m dealing with following issue with Kotlin/Java Compiler.
Imagine following scenario: let First be a Java class with a final function and Second be a Kotlin class extending First with a function of the same name like the final function in First class, example:
// Java class
class First {
final void foo() { }
}
// Kotlin class
class Second: First() {
fun foo() { }
}
Obviously, it’s wrong because the final function foo() can not be overridden. However, compilation pass successfully and in run-time I get java.lang.LinkageError: Method void Second.foo() overrides final method in class First.
Is this correct behavior of compiler? I supposed that there will be some validations for this case. Thank you!