Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make PrivateModule#binder() non-final #1525

Closed
vlsi opened this issue Jun 17, 2021 · 2 comments
Closed

Make PrivateModule#binder() non-final #1525

vlsi opened this issue Jun 17, 2021 · 2 comments

Comments

@vlsi
Copy link
Contributor

vlsi commented Jun 17, 2021

Use case: I want to add convenience methods to AbstractModule and PrivateModule (for easier Kotlin interop), and the issue is that most of the methods in *Module are protected, so the only way to add convenience methods for me is to subclass AbstractModule and PrivateModule.

However, the sub-classes are purely technical (abstract class KotlinModule : AbstractModule and abstract class KotlinPrivateModule : PrivateModule), so I want to exclude them from "source stack" so the exceptions point to the actual binder use rather than to the common KotlinModule and KotlinPrivateModule.

Here's what I do with AbstractModule, and it more-or-less works:

abstract class KotlinModule : AbstractModule() {
    override fun binder() =
        super.binder().skipSources(KotlinModule::class.java) // <-- Here I configure binder to ignore KotlinModule class

    protected inline fun <reified T : Any> bind() = bind(typeLiteral<T>())
    protected inline fun <reified T : Any> bind(name: String) =
        bind<T>().annotatedWith(Names.named(name))
...

The good part is that all default AbstractModule methods like bind(TypeLiteral<T> typeLiteral) use binder() method, so they use the overridden binder(), so all bindings get my skipSources configuration.

Unfortunately, that does not work for PrivateModule since binder() is final there.

abstract class KotlinPrivateModule : PrivateModule() {
    override fun binder() = // <-- this does not compile since binder() is final in PrivateModule
        super.binder().skipSources(KotlinModule::class.java)

    protected inline fun <reified T : Any> bind() = bind(typeLiteral<T>())
...

An alternative option is to make default bind(..) methods public, so Kotlin/Scala extensions could be added without subclassing AbstractModule.

@ronshapiro
Copy link
Collaborator

ronshapiro commented Jun 17, 2021 via email

@vlsi
Copy link
Contributor Author

vlsi commented Jun 17, 2021

What about using extension methods instead of subclassing?

@ronshapiro , extension methods cannot use protected APIs

inline fun <reified T : Any> AbstractModule.bind() =
    bind(typeLiteral<T>()) // <-- error here: Cannot access 'bind': it is protected in 'AbstractModule'

Unfortunately, all Guice methods are declared as protected, so there's no way to extend it without subclassing.

Frankly speaking, I would love to make methods public rather than protected (e.g. extract interfaces for PrivateModule, AbstractModule) , however, that is probably, another issue.

vlsi added a commit to vlsi/guice that referenced this issue Jan 24, 2022
…n subclasses

One of the case for overriding #binder() would be calling Binder#skipSources(...)

fixes google#1525
copybara-service bot pushed a commit that referenced this issue Apr 18, 2023
…n subclasses. Fixes #1569 & fixes #1525. (The primary use-case for this is to override binder() to always call skipSources, like many AbstractModule impls.)

PiperOrigin-RevId: 525202255
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment