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

jvincek :

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)?

tynn :

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)
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=430540&siteId=1