Category Archives: Kotlin

How to Correctly Bind Instances With Guice

Yesterday I have had a weird experience with Guice. I always thought that I pretty much knew what it did when you restricted yourself to the simpler binding methods, such as toInstance or toProvider. Take a look at this (Kotlin) code:

class GuiceTest {
  private val context = Context().apply {
    field = "foo"
  }
 
  @Test
  fun `<code>service can be created`</code>() {
    val injector = Guice.createInjector(
      Module { it.bind(Context::class.java).toInstance(context) }
    )
    assertThat(injector.getInstance(Service::class.java).context.field, equalTo("foo"))
  }
}
 
class Service @Inject constructor(val context: Context)
 
class Context {
  @Inject lateinit var field: String
}

This looks pretty much straight-forward: there’s a Service, it has a Context that is to be injected, the context itself has a field that is also to be injected. In the test a context with an initialized field is created, and this context is supplied to Guice when the injector is created.

Now, if you run this code, you will see that the test fails, because the empty string "" does not equal the string "foo". This is certainly true but—why? What the heck is going on?

As it turns out, toInstance does actually more than simply taking the given object and supplying it everywhere a Context needs to be injected. It does that but, and this causes the observed behaviour, it also runs injection on the given object! So what it does is to try to inject a String into field; String does not have any @Inject-able constructors so the default constructor is used which creates the empty string we see in the test: "". So while Guice itself does not create any new objects it overwrites the field in the object that we created in the test.

Luckily, the fix for this is also straight-forward: use a provider. With Kotlin this is painless:

val injector = Guice.createInjector(
  Module { it.bind(Context::class.java).toProvider { context } }
)

When using a provider the returned value is taken as is. No injection is performed, Guice will simply inject it everywhere a Context is expected—which is what we wanted in the first place.

Sone Is Being Kotlinized

About a year ago Jetbrains released Kotlin 1.0, a new JVM-based programming language. I took a short look at it and pretty much immediately fell in love with it: it is very similar to Java, uses considerably less boiler-plate, has properties, improved collection interfaces (while using all the known java.util stuff under the hood), and lambdas.

I started to introduce it in the company I currently work for and nobody who has used it for more than two lines wants to go back to writing Java code.

Needless to say, I started using it for my private projects, too. One of the good things about Kotlin is that it integrates with existing Java code very nicely. Compiling Java and Kotlin source code with Gradle with both parts depending on the other works out of the box. Java code can use Kotlin classes and the other way around with pretty much no restriction. This makes it very easy to update existing projects: write new code in Kotlin, continue using the old Java code until it’s time to replace it.

So far, Sone profitted from Kotlin most of all: as I am in the process of writing lots and lots of tests for everything that Sone does (and it is amazing how many bugs you find once you actually unit test your code) the news tests will – of course – be written in Kotlin. I also already added some new features to Sone, again using Kotlin.

Several places in Sone collect elements (such as posts) from all over the place, filter them, sort them, all using Guava and Java 1.6-compatible syntax only. This requires a lot of extra code to be written. Take a look at this:

Collection<Post> posts = new ArrayList<>(sone.getPosts());
for (String friend : sone.getFriends()) {
    Optional<Sone> friendSone = core.getSone(friend);
    if (!friendSone.isPresent()) {
        continue;
    }
    posts.addAll(friendSone.get().getPosts());
}
posts.addAll(core.getDirectedPosts(sone));
posts = Collections.filter(posts, Post.FUTURE_FILTER);
posts = Collections.sort(posts, Post.DESCENDING_BY_TIME);

Code very similar to this exists in several places in Sone. Now take a look at the equivalent Kotlin code:

val posts = (sone.posts +
        sone.friends.mapNotNull { core.getSone(it) }.map { it.posts } +
        core.getDirectedPosts(sone))
        .filter { it.time <= System.currentTimeMillis() }
        .sortedByDescending { it.time }

Now go ahead and tell me that this isn’t better (this even works for almost arbitrary definitions of “better.” Yes, Kotlin is just that good).

In addition to actually making me want to work on Sone again it will also reduce the amount of production code in Sone, making it easier to review. However, as I don’t expect any review activity to take place before 2030 (and probably not even before the Great Singularity™) this was not a criterium which played any role in my decision to gradually convert Sone to Kotlin.

Simply put: Kotlin makes programming fun again.