Guice DSL extensions for Kotlin

Overview

kotlin-guice

Guice extensions for Kotlin. This provides extension wrappers and extension methods for providing a better Guice DSL experience from Kotlin. It takes advantage of reified types to reduce class references like bind(MyResource::class.java) to bind<MyResource>().

Download

Download the latest JAR via Maven:

<dependency>
  <groupId>dev.misfitlabs.kotlinguice4</groupId>
  <artifactId>kotlin-guice</artifactId>
  <version>1.5.0</version>
</dependency>

or Gradle:

compile 'dev.misfitlabs.kotlinguice4:kotlin-guice:1.5.0'

Getting Started

KotlinModule

Use KotlinModule for Guice modules instead of AbstractModule to take advantage of the enhanced Kotlin Guice DSL.

import dev.misfitlabs.kotlinguice4.KotlinModule

class MyModule : KotlinModule() {
    override fun configure() {
        bind<Service>().to<ServiceImpl>().`in`<Singleton>()
        bind<PaymentService<CreditCard>>().to<CreditCardPaymentService>()
        bind<CreditCardProcessor>().annotatedWith<PayPal>().to<PayPalCreditCardProcessor>()
    }
}

The KotlinPrivateModule can also be used if only some bindings need to be exposed.

import dev.misfitlabs.kotlinguice4.KotlinPrivateModule

class MyPrivateModule : KotlinPrivateModule() {
    override fun configure() {
        bind<Service>().to<ServiceImpl>().`in`<Singleton>()
        bind<PaymentService<CreditCard>>().to<CreditCardPaymentService>()
        bind<CreditCardProcessor>().annotatedWith<PayPal>().to<PayPalCreditCardProcessor>()
        
        expose<PaymentService<CreditCard>>()
    }
}

Injector

The Guice injector has been enhanced with extension methods to make direct use of the injector better from Kotlin.

import dev.misfitlabs.kotlinguice4.annotatedKey
import dev.misfitlabs.kotlinguice4.getInstance

fun main(args: Array<String>) {
  val injector = Guice.createInjector(MyModule(), MyPrivateModule())
  
  val paymentService = injector.getInstance<PaymentService<CreditCard>>()
  
  // Use the annotatedKey to get an annotated instance
  val payPalProcessor = injector.getInstance(annotatedKey<CreditCardProcessor, PayPayl>())
}

Key and TypeLiteral

Package level functions are included to enhance creating Key and TypeLiteral instances from kotlin.

import dev.misfitlabs.kotlinguice4.annotatedKey
import dev.misfitlabs.kotlinguice4.key
import dev.misfitlabs.kotlinguice4.typeLiteral

val key = key<String>()
val annotatedKey = annotatedKey<String, SomeAnnotation>()
val sameAnnotatedDifferentKey = annotatedKey.getType<Long>()

val listType = typeLiteral<PaymentService<CreditCrd>>()

Multibindings

As of version 1.4.1 the kotlin-guice-multibindings module is gone and the functionality has been merged into kotlin-guice.

Usage

val multibinder = KotlinMultibinder.newSetBinder<Snack>(kotlinBinder)
multibinder.addBinding().to<Twix>()

val mapbinder = KotlinMapBinder.newMapBinder<String, Snack>(kotlinBinder)
mapbinder.addBinding("twix").to<Twix>()

With Guice 4.2+, scanning for methods with the multibinding annotations ProvidesIntoSet, ProvidesIntoMap, and ProvidesIntoOptional is enabled by default. However, the default scanner only provides bindings for Java collection types. In order to get bindings for Kotlin collection types, install the KotlinMultibindingsScanner.

install(KotlinMultibindingsScanner.asModule())

License

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • fix issue with binder caching in kotlin module

    fix issue with binder caching in kotlin module

    unfortunately protected val kotlinBinder: KotlinBinder by lazy { does not always work fine and can cache wrong binder. As result guice can't find some dependencies even these are declared.

    please take a look test that confirm this issue here https://github.com/ashirman/kotlin_guice_bind_error_test

    it is fairly easy to cache "wrong" binder for Kotlin module. Eg val elements = Elements.getElements(modules). it uses RecordingBinder which is cached by Kotlin module after first usage.

    the only solution that I was able to find saving backward compatibility is to delete by lazy { for kotlinBinder: KotlinBinder.

    opened by ashirman 11
  • Support bindInterceptor on final classes

    Support bindInterceptor on final classes

    Since everything is final by default in kotlin, guice's interceptors don't immediately work, and in fact silently fail. This is not hard to google a solution to, assuming you have tests around the caching; however, the kotlin wrapper should either detect this and raise an error, or (ideally) provide a solution (perhaps an open delegating proxy) that allows aop to work.

    opened by reubenfirmin 6
  • Release is still pointing dependencies to Kotlin JRE

    Release is still pointing dependencies to Kotlin JRE

    Hello,

    Just to let you know that the released version on maven central (the one being pulled by gradle) is still pointing its kotlin dependencies to org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.4-3

    Pull Request #4 fixes this on master, but the release was never officially made it seems.

    This is causing a few jar clashes between Kotlin versions locally.

    Cheers

    opened by Hydragyrum 6
  • Multibindings broken with guice 5.1.0: BINDING_ALREADY_SET

    Multibindings broken with guice 5.1.0: BINDING_ALREADY_SET

    The recently released guice 5.1.0 appears to change something that breaks the way the KotlinMultibinder binds the Set (and I think similar for the way the KotlinMapBinder binds the Map) and it appears that both the guice native multibinder and the kotlin-guice KotlinMultibinder are attempting to set the same binding. Looking at the commit list, probably related to https://github.com/google/guice/commit/e6ec2a4a9433d64e763093a826eecf49f005aa5d and https://github.com/google/guice/commit/a260458b28b2dad9e2c8cfca2a2783e585784ab6 ?

      spek2:KotlinMultibinderSpec:KotlinMultibinder:@ProvidesIntoSet:binds complex types into an annotated set
        => com.google.inject.CreationException: Unable to create injector, see the following errors:
    1) [Guice/BindingAlreadySet]: Set<? extends Callable<A>> annotated with @Annotated() was bound multiple times.
    Bound at:
    1  : KotlinMultibinderSpec$1$1$4$4$injector$1.provideAnnotatedACallable(KotlinMultibinderSpec.kt:298)
          \_ installed by: KotlinMultibinderSpec$1$1$4$4$injector$1 -> RealMultibinder
    2  : KotlinMultibinderSpec$1$1$4$4$injector$1.provideAnnotatedACallable(KotlinMultibinderSpec.kt:298)
          \_ installed by: KotlinMultibinderSpec$1$1$4$4$injector$1 -> RealKotlinMultibinder
    Learn more:
      https://github.com/google/guice/wiki/BINDING_ALREADY_SET
    2) [Guice/BindingAlreadySet]: Set<? extends Callable<A>> was bound multiple times.
    Bound at:
    1  : KotlinMultibinderSpec$1$1$4$4$injector$1.provideUnannotatedACallable(KotlinMultibinderSpec.kt:309)
          \_ installed by: KotlinMultibinderSpec$1$1$4$4$injector$1 -> RealMultibinder
    2  : KotlinMultibinderSpec$1$1$4$4$injector$1.provideUnannotatedACallable(KotlinMultibinderSpec.kt:309)
          \_ installed by: KotlinMultibinderSpec$1$1$4$4$injector$1 -> RealKotlinMultibinder
    Learn more:
      https://github.com/google/guice/wiki/BINDING_ALREADY_SET
    2 errors
    ======================
    Full classname legend:
    ======================
    A:                                        "dev.misfitlabs.kotlinguice4.multibindings.A"
    Annotated:                                "dev.misfitlabs.kotlinguice4.multibindings.Annotated"
    Callable:                                 "java.util.concurrent.Callable"
    KotlinMultibinderSpec$1$1$4$4$injector$1: "dev.misfitlabs.kotlinguice4.multibindings.KotlinMultibinderSpec$1$1$4$4$injector$1"
    RealKotlinMultibinder:                    "dev.misfitlabs.kotlinguice4.multibindings.RealKotlinMultibinder"
    RealMultibinder:                          "com.google.inject.internal.RealMultibinder"
    ========================
    End of classname legend:
    ========================
           com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:576)
           com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:163)
           com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
           com.google.inject.Guice.createInjector(Guice.java:87)
           com.google.inject.Guice.createInjector(Guice.java:69)
           com.google.inject.Guice.createInjector(Guice.java:59)
           dev.misfitlabs.kotlinguice4.multibindings.KotlinMultibinderSpec$1$1$4$4.invoke(KotlinMultibinderSpec.kt:290)
           dev.misfitlabs.kotlinguice4.multibindings.KotlinMultibinderSpec$1$1$4$4.invoke(KotlinMultibinderSpec.kt:37)
           org.spekframework.spek2.runtime.scope.TestScopeImpl.execute(Scopes.kt:94)
           org.spekframework.spek2.runtime.Executor$execute$$inlined$executeSafely$lambda$1$1.invokeSuspend(Executor.kt:52)
           [...]
    
    opened by josephlbarnett 5
  • Upgrade Guice to 5.0.1 and Kotlin to 1.4.32

    Upgrade Guice to 5.0.1 and Kotlin to 1.4.32

    This upgrades:

    • Guice to 5.0.1
    • Kotlin to 1.4.32

    Guice 5.0.1 replaces cglib which removes a ton of 'illegal reflective access' warnings that previously came from Guice when running it on newer versions of JVM.

    opened by jsfr 4
  • Null provider message isn't specific

    Null provider message isn't specific

    I'm testing my module using mocks. I'm not supplying a particular property (somewhere). I get the following error message:

    com.google.inject.CreationException: Unable to create injector, see the following errors:
    
    1) Binding to null instances is not allowed. Use toProvider(Providers.of(null)) if this is your intended behaviour.
      at com.authzee.kotlinguice4.internal.KotlinBindingBuilder.toInstance(KotlinBindingBuilder.kt)
    
    1 error
    

    Please ensure you are naming the null property in this message, otherwise it's extremely hard to track down.

    opened by reubenfirmin 4
  • Better @Named binding support

    Better @Named binding support

    Currently, regular bindings can use .annotatedWith(Names.named(name)) to do a named binding, but fall back to regular Guice, rather than kotlin-guice after doing so:

    bind<Interface>().annotatedWith(Names.named(name)).to(Implementation::class.java)

    instead of being able to do something like:

    bind<Interface>().annotatedWith(Names.named(name)).to<Implementation>() or, potentially something like: bind<Interface>().named(name).to<Implementation>()

    On the Multibinding support, it doesn't appear that named bindings are supported at all, and need to fall back fully to regular Guice: Multibinder.newSetBinder(binder(), Interface::class.java, Names.named(name)).addBinding().to(Implementation::class.java)

    instead of being able to do something like:

    KotlinMultibinder.namedSetBinder<Interface>(kotlinBinder, name).addBinding().to<Implementation>()

    opened by josephlbarnett 1
  • Replace dependency on JRE8 with JDK8

    Replace dependency on JRE8 with JDK8

    Including the JRE package results in Gradle build warnings about it being deprecated. See http://kotlinlang.org/docs/reference/whatsnew12.html#kotlin-standard-library-artifacts-and-split-packages.

    opened by j-mew-s 1
  • Guice 4.2

    Guice 4.2

    Hi,

    Small PR with a few updates to kotlin, guice, and other dependencies.

    I've removed the separate multibinding module because since guice 4.2 it's part of core. Moved everything related to multibinding into the main module.

    Let me know what you think.

    Cheers.

    opened by hcura 1
  •  Upgrade to Guice 4.2

    Upgrade to Guice 4.2

    With Guice 4.2 the guice-multibindings extension was merged into Guice core. This commit mirrors that change such that the kotlin-guice-multibindings files are not part of kotlin-guice and the kotlin-guice-multibindings module has been removed.

    opened by johnlcox 0
  • replace TyppeLiteral anonymous-object syntax with KType

    replace TyppeLiteral anonymous-object syntax with KType

    the extensive use of this function:

    https://github.com/misfitlabsdev/kotlin-guice/blob/7d2a0523b4449da0b2d80e1217a052a3d881753d/kotlin-guice/src/main/kotlin/dev/misfitlabs/kotlinguice4/TypeLiteral.kt#L29

    means you are going to end up with a lot of class files pretaining to anonymous overloads. The TypeLiteral hack was added by google as a clever way to avoid type-erasure.

    But in a library such as this, I believe you should use java.lang.reflect.Type and kotlin.reflect.KType, which each do not suffer from type-erasure and will not require any additional *.class files.

    If you're unfamiliar with java.lang.reflect.Type, its effectively wrappers on fully-qualified class strings such as "java.util.ArrayList<? extends java.lang.String>" and they can be used to preserve generic info, making them the obvious choice for guice-binding logic, they're just difficult for users to handle correctly.

    I suggest using something like this:

    inline fun <reified T> kotlinTypeKey(
            annotation: Annotation? = null,
            annotationType: KClass<out Annotation>? = null
    ): Key<T> {
        if(annotation != null) require(annotationType == null)
        if(annotationType != null) require(annotation == null)
    
        val ktype = typeOf<T>()
        val baseType = ktype.javaType
    
        val result = when {
            annotation != null -> Key.get(baseType, annotation)
            annotationType != null -> Key.get(baseType, annotationType.java)
            else -> Key.get(baseType)
        }
    
        @Suppress("UNCHECKED_CAST")
        return result as Key<T>
    }
    

    Once completed, there should be a (measurable) reduction in class files and possibly a measurable increase in performance, particularly for slow hard-drive computers using *.class file distributions (rather than jar distributions).

    an implementation note:

    while this is technically 1.3 compatible, on 1.3.61 the javaType extension in kotlin-jvm will throw. Unfortunately this cant be solved via a simple if-statement because if you expose

    public inline fun <reified T> someBindWrapper(...) {
      if(version == "1.4") {
        //do lightweight j.l.r.Type & KType binding
        doBinding(typeOf<T>())
      }
      else {
        //use heavyweight anonymous typeLiteral overload
        doBinding(object: TypeLiteral<T>(){}) //<-- generates a class file
      }
    }
    

    then, of course, because the if statement cannot be done at compile time, the compiler will generate the class files that we're trying to avoid in the first place! While the native community might solve this with something like #IFDEF KOTLIN_1_4, for better and for worse we have no such device

    I'm really not sure what an elegent solution here is:

    • You could of course create a separate release for 1.4+ and 1.0-1.3, but that's cloogy and opens the door for version hell.
    • You could simply wait to introduce such a patch until 1.4 becomes main-stream, and then add a hard-dependency on kotlin 1.4.
    • You could shadow (read: copy and paste into a new package) the javaType extension function from 1.4. Its not huge and its not too dependent on kotlin 1.4, but it is a reasonably sophisticated string parser and it is responsible for mapping things like kotlin.String to java.lang.String, and kotlin.collections.List<A> to java.util.List<? extends A>.

    Anyways, if you're interested, I'd be happy to give an implemenation a try and issue a pull request!

    opened by Groostav 3
Owner
Misfit Labs
Misfit Labs
A scope tree based Dependency Injection (DI) library for Java / Kotlin / Android.

Toothpick (a.k.a T.P. like a teepee) Visit TP wiki ! What is Toothpick ? Toothpick is a scope tree based Dependency Injection (DI) library for Java. I

Stéphane Nicolas 1.1k Jan 1, 2023
Lightweight, minimalistic dependency injection library for Kotlin & Android

‼️ This project is in maintenance mode and not actively developed anymore. For more information read this statement. ‼️ Katana Katana is a lightweight

REWE Digital GmbH 179 Nov 27, 2022
Painless Kotlin Dependency Injection

KOtlin DEpendency INjection Kodein-DI is a very simple and yet very useful dependency retrieval container. it is very easy to use and configure. Kodei

null 2.9k Jan 1, 2023
Koin - a pragmatic lightweight dependency injection framework for Kotlin

What is KOIN? - https://insert-koin.io A pragmatic lightweight dependency injection framework for Kotlin developers. Koin is a DSL, a light container

insert-koin.io 7.8k Jan 8, 2023
Gits-android-extensions - A collection of Kotlin extensions to simplify Android development

gits-android-extensions A collection of Kotlin extensions to simplify Android de

GITS Indonesia 3 Feb 3, 2022
Google Guice on Android, version 3.0 [RETIRED]

As of August 2016, RoboGuice is no longer supported. For nearly 5 years it was the #1 dependency injection framework on Android due to its ease-of-use

null 3.8k Dec 26, 2022
Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 6 and above, brought to you by Google.

Guice Latest release: 5.0.1 Documentation: User Guide, 5.0.1 javadocs, Latest javadocs Continuous Integration: Mailing Lists: User Mailing List Licens

Google 11.7k Jan 1, 2023
Kotlin-client-dsl - A kotlin-based dsl project for a (Client) -> (Plugin) styled program

kotlin-client-dsl a kotlin-based dsl project for a (Client) -> (Plugin) styled p

jackson 3 Dec 10, 2022
A lightweight Kotlin DSL to render DSL style Json to String.

A lightweight Kotlin DSL to render DSL style Json to String.

null 4 May 5, 2021
FlowExt is a Kotlin Multiplatform library, that provides many operators and extensions to Kotlin Coroutines Flow

FlowExt | Kotlinx Coroutines Flow Extensions | Kotlinx Coroutines Flow Extensions. Extensions to the Kotlin Flow library | kotlin-flow-extensions | Coroutines Flow Extensions | Kotlin Flow extensions | kotlin flow extensions | Flow extensions

Petrus Nguyễn Thái Học 151 Jan 1, 2023
A collection of hand-crafted extensions for your Kotlin projects.

Splitties Splitties is a collection of small Kotlin multiplatform libraries (with Android as first target). These libraries are intended to reduce the

Louis CAD 2.2k Dec 25, 2022
A collection of hand-crafted extensions for your Kotlin projects.

Splitties Splitties is a collection of small Kotlin multiplatform libraries (with Android as first target). These libraries are intended to reduce the

Louis CAD 2.2k Dec 25, 2022
Kotlin extensions for Moshi, Make every thing you want with Moshi in just one line.

Kotlin extensions for Moshi, Make every thing with square / Moshi in one line.

Mazen Rashed 15 Nov 21, 2021
Kotlin extensions, BindingAdapters, Composable functions for Android CameraX

Setup dependencies { implementation "com.github.skgmn:cameraxx:0.6.0" } Features CameraXX provides extensions methods for CameraX to use functions

null 12 Aug 9, 2022
Kotlin extensions of BlurHash for ImageView, Glide, Coil, Piccasso, and fast loading BlurHashDrawable optimized for Android.

Kotlin extensions of BlurHash for ImageView, Glide, Coil, Piccasso, and fast loading BlurHashDrawable optimized for Android.

Nosakhare Belvi 115 Dec 20, 2022
Quarkus Sample Application with extensions cache, kotlin, rest client, resteasy and smallrye

quarkus-sample Project This project uses Quarkus, the Supersonic Subatomic Java Framework. If you want to learn more about Quarkus, please visit its w

Erdem Aydın 1 Sep 25, 2022
A "fluent" OkHTTP library for Kotlin based on string extensions.

okfluent A "fluent" OkHTTP library for Kotlin based on string extensions. Do not take this project seriously, I just wanted to show that this kind of

Duale Siad 0 Nov 23, 2021
🤹 Common Kotlin utilities made for my personal usage, comes with SLF4J utilities, common extensions, common Gradle utilities, and more.

?? common-utils Common Kotlin utilities made for my personal usage, comes with SLF4J utilities, common extensions, ansi-colours, common Gradle utiliti

Noel ʕ •ᴥ•ʔ 6 Dec 2, 2022
Set of extensions for Kotlin that provides Discrete math functionalities

DiscreteMathToolkit Set of extensions for Kotlin that provides Discrete Math functionalities as an Kotlin extension functions. To stay current with ne

Marcin Moskała 177 Dec 15, 2022
Common Android/Kotlin extensions

Common Android/Kotlin extensions Gradle implementation "com.github.javokhirsavriev:common-extensions:1.0.1" License Copyright 2022 Javokhir Savriev L

Javokhir 0 Feb 15, 2022