DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • The Window Closes: Why I Switched to Kotlin Before the Codebase Got Too Big
  • Testing Java and Spring Applications With Kotlin: Low-Risk to Adoption
  • Why Kotlin or Java Is the Wrong Question For Enterprises
  • Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot

Trending

  • Introduction to Error Prone: How to Catch Bugs at Compile Time
  • How to Migrate From C/C++ to Rust: A Practical Guide for Embedded IoT Systems
  • Why AI Agents Need a Shared Enterprise Ontology
  • Running a Self-Hosted WAF in Production: Practical Lessons From SafeLine

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Coding
  3. Languages
  4. Kotlin + Guice Example

Kotlin + Guice Example

By 
Alex Tkachman
·
Feb. 04, 12 · Interview
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
33.5K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

While Kotlin programming language prepares for the public early access program I want to share with you one an example how easly it can be used with existing Java codebases.

This short note does not intend to teach the reader how to use Kotlin but only to make him/her intersted to learn.


We will create small toy application using Kotlin and the charming Guice framework.  The application is nothing more than the usual "Hello, World!" but it contains an application service and logging service and each service will have two incarnations - for testing and for production use.

Let us start with an abstract LoggingService. It will be an abstract class with only one abstract method to output the passed string. Most probably the code below does not require much explaination.

abstract class LoggingService() {
    abstract fun info(message: String?)
}

Now we will define a simple implementation, which prints the given message to the standard output

class StdoutLoggingService() : LoggingService(){
    override fun info(message: String?) = println("INFO: $message")
}

override modifier tells the compiler that the method overrides some method of a superclass.

Note also string interpolation

Now we will create a little more sophisticated implementation, which we will use in production :)

class JdkLoggingService [Inject] (protected val jdkLogger: Logger) : LoggingService() {
    override fun info(message: String?)  = jdkLogger.info(message)
}

[Inject] annotation on constructor tells Guice how to create JdkLoggerService.

val on constructor parameter asks to create final property initialized by given value. var asks for non-final one and neither of them define simple constructor parameter

Now we are ready to define the abstract application service and both implementations of it for test and production use.

abstract class AppService(protected val logger: LoggingService, protected val mode: String) {
    fun run() {
        logger.info("Application started in '$mode' mode with ${logger.javaClass.getName()} logger")
        logger.info("Hello, World!")
    }
}

class RealAppService [Inject] (logger: LoggingService) : AppService(logger, "real")

class TestAppService [Inject] (logger: LoggingService) : AppService(logger, "test")

Note how elegantly Kotlin allows us to define properties and pass values to superconstructor 

Now we go to more interesting part - creating min-DSL for Guice. But let us start with how we want our application to look like.

fun main(args: Array<String>) {
    fun configureInjections(test: Boolean) = injector {
        +module {
            if(test) {
                bind<LoggingService>().toInstance (StdoutLoggingService())
                bind<AppService>().to<TestAppService> ()
            }
            else {
                bind<LoggingService>().to<JdkLoggingService>()
                bind<AppService>().to<RealAppService> ()
            }
        }
    }

    configureInjections(test=false).getInstance<AppService> ().run()
}

There are few things to notice here

  1. We use local function to configure injections. It is not necessary but allow some nice code grouping.
  2. Return type of function configureInjections is inferred from it's body (call to finction injector - root of our DSL which we will define soon)
  3. We call configureInjections using named arguments syntax. It is not necessary in our case but very convinient when we have many parameters and some of them are optional.

Now it is time to define simple parts of our DSL. It will be three extension functions for some Guice classes.

fun <T> Binder.bind() = bind(javaClass<T>()).sure()

fun <T> AnnotatedBindingBuilder<in T>.to() = to(javaClass<T>()).sure()

fun <T> Injector.getInstance() = getInstance(javaClass<T>())
  1. Please read about extension functions in Kotlin documentation
  2. Note in variance used in function 'to'. Please read about generics and variance in Kotlin documentation. It is really interesting
  3. javaClass<T>() call is Kotlin standard library for Java (remember that Kotlin can be compiled for other platforms like javascript as well) is equivalent to T.class in Java. The huge difference here is that in Kotlin it applicable not only to real classes but also to generic type parameters (thanks to runtime type information).
  4. Call to method sure() is Kotlin way (soon to be replaced by special language construct) to ensure non-nullability. As Java has not notation of nullable and non-nullable types we need to take some care on integration point. Please read amazing story of null-safety in Kotlin documentation.

Finally we are ready to most complex part - definition of method injector.

fun injector(config: ModuleCollector.() -> Any?) : Injector {
    val collector = ModuleCollector()
    collector.config()
    return Guice.createInjector(collector.collected).sure()
}

It has one parameter of type ModuleCollector.()->Any? which means "extension function for ModuleCollector(we will define ModuleCollector few lines below), which does not accept any parameters and returns value of any type potentially nullable"

The implementation is very straight-forward

  1. we create ModuleCollector
  2. we use it as receiver to call given configuration function
  3. we ask Guice to create Injector for all modules configured (consult Guice documentation for details) 

This is extremely powerful method of defining DSLs in Kotlin

As we saw above we call method injector with function block expression.

The fact that parameter is extension function makes all (modulo visibility rules) methods of ModuleCollector available inside function block.

The last part of our DSL is definition of ModuleCollector.

It contains internal list of collected modules and only two methods

  • method module - uses variation of the same extension-function-as-parameter trick - we use extension function to implement method of anonimous class.
Please consult Kotlin documentation on object expressions
  • method plus - overrides unary plus operation
Please consult Kotlin documentation on operator overloading.

It is very important to note that this method is both extension method and member of class ModuleCollector. It allows very good context catching on call site. In our case above we call this method inside extention function with ModuleCollectoror receiver and apply it to Module created by call to method Module.
class ModuleCollector() {
    val collected = ArrayList<Module> ()

    fun module (config: Binder.()->Any?) : Module = object: Module {
        override fun configure(binder: Binder?) {
            binder.sure().config()
        }
    }

    fun Module.plus() {
        collected.add(this)
    }
}

We are done. I hope that was interesting. This note is a very brief and non-detailed introduction on goodies of Kotlin.  If this has motivated you to read more about Kotlin then my goal is achieved.

Thank you and till next time!

Kotlin (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • The Window Closes: Why I Switched to Kotlin Before the Codebase Got Too Big
  • Testing Java and Spring Applications With Kotlin: Low-Risk to Adoption
  • Why Kotlin or Java Is the Wrong Question For Enterprises
  • Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook