# Quick Bites: Discovering a Bug in the Kotlin Compiler

## Summary

I was working with a Kotlin class which extended a Java class and the Kotlin class defined a less-accessible property with the same name as a more-accessible field of the Java class and I ran into an `IllegalAccessError`.

[It's now filed as a bug to the Kotlin team at JetBrains.](https://youtrack.jetbrains.com/issue/KT-54393/Change-in-behavior-from-1710-to-1720-for-java-field-override)

## Background

### About Kotlin

[Kotlin](https://kotlinlang.org/) is a JVM-based language and one of its selling points is that it seamlessly works with any existing Java code. This interoperability of Kotlin lets you start using it without the worry of rewriting or throwing away the millions of lines of Java which your organization has already written and depends on.

### Kotlin Properties

[Kotlin's properties feature](https://kotlinlang.org/docs/properties.html) is a succinct way of defining getters and setters for a variable in a class.

```kotlin

class Foo {
  public val fooProperty: String
    get() = "Fooooo"
}
```

Another shortcut available in Kotlin is to define the properties of a class by specifying them in the constructor:

```kotlin

// The Kotlin way
class FooBar(private val foo: String, private val bar: String) { }

// The above is equivalent to this in Java
class FooBar {
  private String foo;
  private String bar;

  public FooBar(String foo, String bar) {
    this.foo = foo;
    this.bar = bar;
  }
}
```

### A bad Cocktail of Kotlin and Java

Now, let's say you have the following Java class:

```java
class JavaClass {
  public String injectedField;
}
```

and your Kotlin class extended this class as:

```kotlin
 class KotlinClass(private val injectedField: String): JavaClass() {
  fun printInjectedField(): String { 
    println(injectedField)
  }
}
```

You would expect the following behavior:
- `JavaClass` superclass has a field with the same name `injectedField` as `KotlinClass`'s private property,
- The Kotlin property will be accessed in `printInjectedField` as there is no usage of the `super` keyword.

When you run the above code you will be met with an `IllegalAccessError` as the `printInjectedField` function will try to access the `injectedField` value in the Java superclass.

## How it was caught

### Guice's Field Injection is Ugly

The setup for the error is contrived and you would only run into in few special cases. One such case is with [Guice's field injection](https://github.com/google/guice/wiki/Injections#field-injection).

The Java class which our Kotlin class extended from was using field injection in many places (which is a code smell). We were passing these dependencies to the Kotlin class via its constructor and we were puzzled whenever we ran into the `IllegalAccessError` as we were sure that we were referring to the correct instance.

### A Little Help from the Compiler Team

Our first action was to rely on our Googling skills to find something on Stack Overflow and [we failed to find anything useful for us](https://archive.is/tkVmg). After asking this question in Google's version of an internal Stack Overflow, we received a response from the people working on the Kotlin compiler at Google and they suggested to rename the property name (i.e. don't keep the same as the field of the Java superclass).

And that fix worked!

That wasn't the end of the investigation as they followed up with the JetBrains team to identify the root cause of the issue as they were unsure of the behavior themselves and this is now being tracked as a possible bug in the Kotlin compiler: https://youtrack.jetbrains.com/issue/KT-54393/Change-in-behavior-from-1710-to-1720-for-java-field-override

## Lessons

- Java interoperability is good but there might be edge cases which you might unfortunately run into.
- Don't be afraid to reach out to folks working on Kotlin.
- Don't use Guice's field injection if you can avoid it.
