This question about how to make effectively static method implementations for jvm. By effectively static definition I mean jvm static method implementation without rudimentary stateless companion object.
I found this requirement when I need to implement static @Provides
method for dagger (like suggested by "Favor static @Provides
methods"). Let's consider next examples.
Top level function is effectively static
But it can't be referenced by class in annotations (module in dagger)
TestModule.kt
@file:JvmName("TestModule") // <-- does not affect anything in this case
@file:Module // <-- dagger module annotation for generated TestModule class
package com.example
import dagger.Module
import dagger.Provides
/**
* Effectively jvm static implementation (without rudimentary Companion instance)
*/
@Provides
fun getRunnable(): Runnable = Runnable { println(42) }
TestModule.decompiled.java
package com.example;
import dagger.Module;
import dagger.Provides;
import kotlin.Metadata;
import kotlin.jvm.JvmName;
import org.jetbrains.annotations.NotNull;
@Module
@Metadata(
mv = {1, 1, 13},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\b\n\u0000\n\u0002\u0018\u0002\n\u0000\u001a\b\u0010\u0000\u001a\u00020\u0001H\u0007¨\u0006\u0002"},
d2 = {"getRunnable", "Ljava/lang/Runnable;", "status"}
)
@JvmName(
name = "TestModule"
)
public final class TestModule {
/*
Instance of stateless companion object is absent - that what we want to achieve
*/
@Provides
@NotNull
public static final Runnable getRunnable() {
return (Runnable)null.INSTANCE;
}
}
Issue in usage side. TestComponent.kt
package com.example
import dagger.Component
@Component(modules = [TestModule::class /* This name is not available even in compile time */])
interface TestComponent
Rudimentary companion object
When we define module class with companion object we can refer it in annotations but in this case @JvmStatic
methods just delegates for methods from rudimentary companion object instance.
TestModule.kt
package com.example
import dagger.Module
import dagger.Provides
@Module
class TestModule {
companion object {
@Provides
@JvmStatic
fun getRunnable(): Runnable = Runnable { println(42) }
}
}
TestModule.decompiled.java
package com.example;
import dagger.Module;
import dagger.Provides;
import kotlin.Metadata;
import kotlin.jvm.JvmStatic;
import kotlin.jvm.internal.DefaultConstructorMarker;
import org.jetbrains.annotations.NotNull;
@Module
@Metadata(
mv = {1, 1, 13},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\b\u0007\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},
d2 = {"Lru/tensor/sbis/status/domain/assembly/TestModule;", "", "()V", "Companion", "status"}
)
public final class TestModule {
/*
Rudimentary stateless instance can be effectively omitted
*/
public static final TestModule.Companion Companion = new TestModule.Companion((DefaultConstructorMarker)null);
@Provides
@JvmStatic
@NotNull
public static final Runnable getRunnable() {
return Companion.getRunnable(); // <-- delegated method call
}
@Metadata(
mv = {1, 1, 13},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007¨\u0006\u0005"},
d2 = {"Lru/tensor/sbis/status/domain/assembly/TestModule$Companion;", "", "()V", "getRunnable", "Ljava/lang/Runnable;", "status"}
)
public static final class Companion {
@Provides
@JvmStatic
@NotNull
public final Runnable getRunnable() {
return (Runnable)null.INSTANCE;
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
Question
How to refer effectively static stateless implementation of Util (dagger module) class by it name?