kotlinkotlin-extensionkotlin-java-interop

How can I call Kotlin extension function with receiver from the Java static method?


Probably I miss something very simple, but let's imagine I have this extension method in Kotlin:

fun Any.log(message: String) {
    println(this.javaClass.simpleName + message)
}

Is it possible to call it from the static method in Java class?

Note. From the regular instance method, I can do

MyExtensionsKt.log(this, "This is a log message")

But the static method doesn't have an object instance.


Solution

  • You could just pass a random Object in:

    MyExtensionsKt.log(new Object(), "This is a log message");
    

    Of course, this will produce a log message that starts with Object, not the name of the current class.

    To produce a log message that starts with the name of the current class, you would need to either create a new, temporary instance of the current class:

    // suppose the static method is in "SomeClass"
    MyExtensionsKt.log(new SomeClass(), "This is a log message");
    

    or change the implementation of the log method to be a bit smart about its receiver. For example, if it is found that it is a Class, then just directly use its name as the prefix for the log message.

    fun Any.log(message: String) {
        val prefix = if (this is Class<*>) {
            this.simpleName
        } else {
            this.javaClass.simpleName
        }
        println(prefix + message)
    }
    
    // then in SomeClass, you can do:
    
    MyExtensionsKt.log(SomeClass.class, "This is a log message");
    

    If you cannot do either of those things, then I would suggest that you not use a static method. How about the singleton pattern instead?

    Example:

    private static final SomeClass INSTANCE = new SomeClass();
    public static final SomeClass getInstance() { return INSTANCE; }
    
    // now you can have instance methods, and have access to "this"!
    

    Side note:

    Singletons are also how Kotlin's objects are implemented in the JVM.

    object Foo {
        fun foo() { 
            this.log("This is a log message")
        }
    }
    

    When you call Foo.foo(), it may seem like you are calling a "static" method, but you are really just calling Foo.INSTANCE.foo(). Because of this, this is available in Kotlin objects.