简体   繁体   中英

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

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

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

I don't know if it is possible to have delegated methods as static methods inside an object in Kotlin.

However, as you are interested in creating singletons that proxy a class, you could use package-level constants in Kotlin:

val SingletonKt : FacadeInterface<String> = Facade(String::class.java)

Now, you can call SingletonKt.method just like you would in Java. Note that you need to use a static import in Java to be able to use the SingletonKt constant.

This also allows you to use features like lazy to only create the singleton (or, in this case, instance) when you need it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM