1

Let's say I have two interfaces in a project:

interface InterfaceA {
    // ...
    interface Listener {
        // ...
    }
}

interface InterfaceB {
    // ...
    interface Listener {
        // ...
    }
}

and I declare both of them and their listeners for annotation processing using Kotlin Poet's ClassName, eg.

fun InterfaceA() = ClassName(
    packageName = "com.example.a",
    simpleNames = arrayOf("InterfaceA"),
)

fun InterfaceAListener() = ClassName(
    packageName = "com.example.a.InterfaceA",
    simpleNames = arrayOf("Listener"),
)

fun InterfaceB() = ClassName(
    packageName = "com.example.b",
    simpleNames = arrayOf("InterfaceB"),
)

fun InterfaceBListener() = ClassName(
    packageName = "com.example.b.InterfaceB",
    simpleNames = arrayOf("Listener"),
)

The class I have to generate uses all of the aforementioned types: InterfaceA, InterfaceA.Listener, InterfaceB, InterfaceB.Listener. That results in generating the following imports, producing compilation error due to ambigouos Listener imports.

import com.example.a.InterfaceA
import com.example.a.InterfaceA.Listener
import com.example.b.InterfaceB
import com.example.b.InterfaceB.Listener

Is there any way to get rid of the listener imports, since they're not really necessary? Or is there any other way to approach the issue?

Thanks for any help!

Luja93
  • 451
  • 3
  • 8
  • That's not at all what happens. KotlinPoet handles this correctly by using aliased imports for the listeners. Please show a [mcve]. – Sweeper Sep 02 '23 at 15:00
  • 1
    Actually, the way you create `ClassName`s is also incorrect. `Listener` is not in a package called `com.example.a.InterfaceA`. You should do something like `InterfaceB().nestedClass("Listener")`. Either way, KotlinPoet can resolve the conflict. – Sweeper Sep 02 '23 at 15:08
  • Hi, @Sweeper! The nested class is exactly what I needed. Creating `ClassName`s in such a way was a silly mistake on my part. Thanks a lot! – Luja93 Sep 02 '23 at 15:20

1 Answers1

1

The Listeners aren't actually in a package called com.example.a.InterfaceA or com.example.a.InterfaceB. They are nested types in InterfaceA and InterfaceB.

You can create ClassNames representing nested types using the nestedClass method.

Example:

val listenerA = ClassName("com.example", "InterfaceA").nestedClass("Listener")
val listenerB = ClassName("com.example", "InterfaceB").nestedClass("Listener")
FileSpec.builder("", "Foo")
    .addProperty(
        PropertySpec.builder("foo", listenerA).build()
    )
    .addProperty(
        PropertySpec.builder("bar", listenerB).build()
    )
    .build()
    .writeTo(System.out)

This outputs:

import com.example.InterfaceA
import com.example.InterfaceB

public val foo: InterfaceA.Listener

public val bar: InterfaceB.Listener

Notice that only InterfaceA and InterfaceB are imported.


Even if the Listeners are not nested types, and are actually top-level interfaces in different packages. KotlinPoet can still resolve the conflict by using aliased imports.

That is, if you actually did:

val listenerA = ClassName("com.example.InterfaceA", "Listener")
val listenerB = ClassName("com.example.InterfaceB", "Listener")

KotlinPoet would generate:

import com.example.InterfaceA.Listener as InterfaceAListener
import com.example.InterfaceB.Listener as InterfaceBListener
Sweeper
  • 213,210
  • 22
  • 193
  • 313