Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call Kotlin object with class delegation from Java as a static method

Tags:

This may be a bit difficult to describe, so I'll try to give a concrete example of what I'm trying to do.

Suppose we have a Facade interface and class (in Java), like this:

interface FacadeInterface<T> {
    void method(String from, String via);
}

class Facade<T> implements FacadeInterface<T> {
    private Class<T> mClazz;

    public Facade(Class<T> clazz) {
        mClazz = clazz;
    }

    @Override
    public void method(String from, String via) {
        System.out.println("Method called from " + from + " via " + via);
    }
}

In my applications, I need to have multiple singletons which hold an instance of the facade. The real facade has additional setup/config parameters but those are irrelevant here.

Before I started using kotlin, I would have a class which holds a static instance of the facade (not really a singleton, but in my case, it served a similar purpose) which proxied the calls to the facade, like this:

public class Singleton {
    private static final FacadeInterface<String> sFacade = new Facade<>(String.class);

    private Singleton() {
    }

    public static void method(String from, String via) {
        sFacade.method(from, via);
    }
}

Now, with Kotlin we have class delegates which allow me to write something like this:

object SingletonKt : FacadeInterface<String> by Facade(String::class.java)

This is great - no more boilerplate and I can call SingletonKt from Kotlin classes the same way I called the java Singleton:

Singleton.method("Kotlin", "Singleton")
SingletonKt.method("Kotlin", "SingletonKt")

But, a slight problem arises when I use SingletonKt from Java. Then I have to specify INSTANCE:

Singleton.method("Java", "Singleton");
SingletonKt.INSTANCE.method("Java", "SingletonKt");

I am aware of the @JvmStatic annotation, but the only place I can put it in the SingletonKt file without causing compile errors is right before FacadeInterface and it doesn't seem to do the trick.

Is there a way to set up this class delegate so that I can call it from Java as if it were a static method, without introducing the boilerplate of creating proxy methods for SingletonKt (which would defeat the purpose of the class delegate)?

like image 591
jvincek Avatar asked Jun 09 '17 09:06

jvincek


1 Answers

It's sadly not possilble!

The Kotlin Delegation is a nice way to reduce boilerplate code. But it comes with the inability to actually access the delegate within the class body.

The second issue you're facing regarding @JvmStatic is actually more drastic to your cause than the first and also applies to you when implementing the delegation manually:

Override members cannot be '@JvmStatic' in object

So instead of exposing the method() through the INSTANCE only, you could delegate it to a staticMethod() on the object. This still differs from your intent, but comes close to it.

object SingletonKt : FacadeInterface<String> by Facade(String::class.java)
    @JvmStatic fun staticMethod(from: String, via: String) = method(from, to)
}
like image 134
tynn Avatar answered Sep 22 '22 14:09

tynn