0

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?

Sergei Bubenshchikov
  • 5,275
  • 3
  • 33
  • 60
  • I one asked this question https://stackoverflow.com/questions/44894218/dagger-2-static-provider-methods-in-kotlin maybe one of the answers helps you with this. – Fred Jan 09 '19 at 07:13
  • @Fred [first answer](https://stackoverflow.com/a/44894535/3926506) - stateless singleton, it's bad practice. [Second answer](https://stackoverflow.com/a/44994441/3926506) it's also stateless singleton but in this case it implicit (companion object instance). The aim is **do not create stateless singletons** – Sergei Bubenshchikov Jan 09 '19 at 07:46
  • There is no syntax for referencing a class generated by the JVM backend to contain top-level functions or properties. – yole Jan 09 '19 at 09:11
  • @yole ok, I understand about syntax. How I can define static functions set without stateless companion object? – Sergei Bubenshchikov Jan 09 '19 at 09:21

0 Answers0