title: Moshi with kotlin generics throws No JsonAdapter for interface
body: <p>Suppose I have an Interface <code>IRunnable</code> and two implementations <code>Cat</code> and <code>Dog</code> :</p>
  
  <pre><code>interface IRunnable {
    fun run()
  }
  
  class Cat : IRunnable {
    override fun run() { println("cat running") }
  }
  
  class Dog : IRunnable {
    override fun run() { println("dog running") }
  }
  </code></pre>
  
  <p>And there is an interface that converts <code>IRunnable</code> to <code>Map&lt;String,String&gt;</code> with key=<code>runnable</code></p>
  
  <pre><code>interface IMapConverter&lt;T&gt; {
    fun getMap(impl : T) : Map&lt;String , String&gt;
    fun getImpl(map : Map&lt;String , String&gt;) : T?
  }
  </code></pre>
  
  <pre><code>class RunnableConverter : IMapConverter&lt;IRunnable&gt; {
    private val key = "runnable"
  
    override fun getMap(impl: IRunnable): Map&lt;String, String&gt; {
      val value = when(impl) {
        is Cat -&gt; "C"
        is Dog -&gt; "D"
        else -&gt; throw RuntimeException("error")
      }
      return mapOf(key to value)
    }
  
    override fun getImpl(map: Map&lt;String, String&gt;): IRunnable? {
      return map[key]?.let { value -&gt;
        when (value) {
          "C" -&gt; Cat()
          "D" -&gt; Dog()
          else -&gt; throw RuntimeException("error")
        }
      }
    }
  }
  </code></pre>
  
  <p>Then with moshi , I want the <code>IMapConverter</code> become a <code>JsonAdapter</code> , so I add a <code>getAdapter()</code> function inside <code>RunnableConverter</code> :</p>
  
  <pre><code>fun getAdapter() : JsonAdapter&lt;IRunnable&gt; {
      return object : JsonAdapter&lt;IRunnable&gt;() {
  
        @ToJson
        override fun toJson(writer: JsonWriter, runnable: IRunnable?) {
          runnable?.also { impl -&gt;
            writer.beginObject()
            getMap(impl).forEach { (key , value) -&gt;
              writer.name(key).value(value)
            }
            writer.endObject()
          }
        }
  
        @FromJson
        override fun fromJson(reader: JsonReader): IRunnable? {
          reader.beginObject()
  
          val map = mutableMapOf&lt;String , String&gt;().apply {
            while (reader.hasNext()) {
              put(reader.nextName() , reader.nextString())
            }
          }
          val result = getImpl(map)
  
          reader.endObject()
          return result
        }
      }
    }
  </code></pre>
  
  <p>It works well :</p>
  
  <pre><code>  @Test
    fun testConverter1() {
      val converter = RunnableConverter()
  
      val moshi = Moshi.Builder()
        .add(converter.getAdapter())
        .build()
  
      val adapter = moshi.adapter&lt;IRunnable&gt;(IRunnable::class.java)
      adapter.toJson(Dog()).also { json -&gt;
        assertEquals("""{"runnable":"D"}""" , json)
        adapter.fromJson(json).also { runnable -&gt;
          assertTrue(runnable is Dog)
        }
      }
    }
  </code></pre>
  
  <p>But , when I want to <strong>externalize</strong> the adapter to a extension function :</p>
  
  <pre><code>fun &lt;T&gt; IMapConverter&lt;T&gt;.toJsonAdapter() : JsonAdapter&lt;T&gt; {
    return object : JsonAdapter&lt;T&gt;() {
  
      @ToJson
      override fun toJson(writer: JsonWriter, value: T?) {
        value?.also { impl -&gt;
          writer.beginObject()
          getMap(impl).forEach { (key , value) -&gt;
            writer.name(key).value(value)
          }
          writer.endObject()
        }
      }
  
      @FromJson
      override fun fromJson(reader: JsonReader): T? {
        reader.beginObject()
  
        val map = mutableMapOf&lt;String , String&gt;().apply {
          while (reader.hasNext()) {
            put(reader.nextName() , reader.nextString())
          }
        }
  
        val result = getImpl(map)
        reader.endObject()
        return result
      }
    }
  }
  
  </code></pre>
  
  <p>And when I want to test the function :</p>
  
  <pre><code>  @Test
    fun testConverter2() {
      val converter = RunnableConverter()
  
      val moshi = Moshi.Builder()
        .add(converter.toJsonAdapter()) // this is extension function
        .build()
  
      val adapter = moshi.adapter&lt;IRunnable&gt;(IRunnable::class.java)
      adapter.toJson(Dog()).also { json -&gt;
        logger.info("json of dog = {}", json)
        assertEquals("""{"runnable":"D"}""" , json)
        adapter.fromJson(json).also { runnable -&gt;
          assertTrue(runnable is Dog)
        }
      }
    }
  </code></pre>
  
  <p>It compiles OK , but reports error :</p>
  
  <pre><code>java.lang.IllegalArgumentException: No JsonAdapter for interface moshi.IRunnable (with no annotations)
  
      at com.squareup.moshi.Moshi.adapter(Moshi.java:148)
      at com.squareup.moshi.Moshi.adapter(Moshi.java:98)
      at com.squareup.moshi.Moshi.adapter(Moshi.java:72)
      at moshi.MoshiTest.testConverter2(MoshiTest.kt:39)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:566)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
      at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
      at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
      at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
  </code></pre>
  
  <p>I try to set breakpoint at line 137 at Moshi.java
  <a href="https://github.com/square/moshi/blob/40a829ef181e7097087ec0e95cdcf3e3fbba3156/moshi/src/main/java/com/squareup/moshi/Moshi.java#L137" rel="nofollow noreferrer">https://github.com/square/moshi/blob/40a829ef181e7097087ec0e95cdcf3e3fbba3156/moshi/src/main/java/com/squareup/moshi/Moshi.java#L137</a></p>
  
  <p>And this is the debug screenshot :</p>
  
  <p>The OK one (defined in <code>RunnableConverter</code>) :
  <a href="https://i.stack.imgur.com/6uL72.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6uL72.png" alt="enter image description here"></a></p>
  
  <p>And this is the generic version created by extension function :
  <a href="https://i.stack.imgur.com/8kZe4.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8kZe4.png" alt="enter image description here"></a></p>
  
  <p>It seems because the type erasure , it cannot work ...
  Is there any way to work around it ?</p>
  
  <p>For anyone who interests in it , the full code is here :
  <a href="https://gist.github.com/smallufo/985db4719c5434a5f57f06b14011de78" rel="nofollow noreferrer">https://gist.github.com/smallufo/985db4719c5434a5f57f06b14011de78</a></p>
  
  <p>environment :</p>
  
  <pre><code>&lt;dependency&gt;
    &lt;groupId&gt;com.squareup.moshi&lt;/groupId&gt;
    &lt;artifactId&gt;moshi-kotlin&lt;/artifactId&gt;
    &lt;version&gt;1.9.2&lt;/version&gt;
  &lt;/dependency&gt;
  </code></pre>
  
  <p>Thanks.</p>