Kotlin: MyClass::class.java vs this.javaClass

Matias Elorriaga picture Matias Elorriaga · Mar 3, 2017 · Viewed 8.5k times · Source

I'm migrating a project to Kotlin, and this:

public static Properties provideProperties(String propertiesFileName) {
    Properties properties = new Properties();
    InputStream inputStream = null;
    try {
        inputStream = ObjectFactory.class.getClassLoader().getResourceAsStream(propertiesFileName);
        properties.load(inputStream);
        return properties;
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}

is now:

fun provideProperties(propertiesFileName: String): Properties? {
    return Properties().apply {
        ObjectFactory::class.java.classLoader.getResourceAsStream(propertiesFileName).use { stream ->
            load(stream)
        }
    }
}

very nice, Kotlin! :P

The question is: this method looks for a .properties file inside src/main/resources. Using:

ObjectFactory::class.java.classLoader...

it works, but using:

this.javaClass.classLoader...

classLoader is null...

enter image description here

enter image description here

enter image description here

(note that the memory address is also different)

Why?

Thanks

Answer

Alexander Udalov picture Alexander Udalov · Mar 3, 2017

If you invoke javaClass inside a lambda passed to apply, it's called on the implicit receiver of that lambda. Since apply turns its own receiver (Properties() in this case) into the implicit receiver of the lambda, you're effectively getting the Java class of the Properties object you've created. This is of course different from the Java class of ObjectFactory you're getting with ObjectFactory::class.java.

For a very thorough explanation of how implicit receivers work in Kotlin, you can read this spec document.