Epoxy: @AutoModel with kotlin generates nonExistentClass

Created on 24 Mar 2017  路  4Comments  路  Source: airbnb/epoxy

The processor find not the generate models (TypeName). I have a fork where the SampleController is in kotlin.
my fork

Most helpful comment

I dug into this yesterday and noticed that the issue was that with the Kotlin code the annotation processor receives a TypeMirror of error.NonExistentClass for the AutoModel fields, since they have not been generated yet. I couldn't figure out a way to get around that so I was about to give up and not support it.

@geralt-encore Thank you for bringing up correctErrorTypes! I read more about it at https://kotlinlang.org/docs/reference/using-gradle.html and it completely fixes the problem.

@markus2610 I did notice that I had to also add apply plugin: 'kotlin-kapt' to the kotlin sample and that generateStubs was not necessary.

You're right that a Kotlin specific example would be useful. At the very least I'll add instructions for what kapt settings to use. I didn't design this for kotlin, and it's unfortunate that fields need to be @AutoModel lateinit var header: HeaderModel_ as it gets a bit verbose compared to java. What I may recommend is not using @AutoModel and just creating the model manually using a string id.

        HeaderModel_()
                .id("header")
                .title(R.string.epoxy)
                .caption(R.string.header_subtitle)
                .addTo(this);


        ButtonModel_()
                .id("add button")
                .text(R.string.button_add)
                .clickListener { model, parentView, clickedView, position -> callbacks.onAddClicked() }
                .addTo(this)

        ButtonModel_()
                .id("clear button")
                .text(R.string.button_clear)
                .clickListener(View.OnClickListener { callbacks.onClearClicked() })
                .addIf(colors.isNotEmpty(), this)

The @AutoModel annotation doesn't give you much over this - it just guarantees a unique id, creates the model, and does some validation that the models are used correctly.

In some ways defining the ids with strings like this is cleaner, since it doesn't split up the model into a field value, and removes the boilerplate of the AutoModel field. The downside is that a string id adds a (very small) chance of id collision, is slightly slower to convert to a long id, and may be a bit confusing for more complicated controllers since you need to manually track the ids and make sure you don't have duplicates (although the runtime validation would throw if you did).

As I've started to integrate Epoxy 2.0 into our app and upgrade adapters to controllers I've noticed that for simpler adapters with just a few @AutoModel fields I actually prefer to remove the @AutoModel usage and define the string id manually

All 4 comments

Thanks for the report, I'll try to look into this soon.

In order to solve it you have to add following line to your build.gradle:

apply plugin: 'kotlin-kapt'

kapt {
  correctErrorTypes = true
}

Basically, the problem is that the first version of kapt isn't able to process generated files. It was solved in kapt3, which will be used if you apply kotlin-kapt plugin with correctErrorTypes option.

@elihart maybe it worth to create a Kotlin sample? Seems like integration is not that straightforward.

I dug into this yesterday and noticed that the issue was that with the Kotlin code the annotation processor receives a TypeMirror of error.NonExistentClass for the AutoModel fields, since they have not been generated yet. I couldn't figure out a way to get around that so I was about to give up and not support it.

@geralt-encore Thank you for bringing up correctErrorTypes! I read more about it at https://kotlinlang.org/docs/reference/using-gradle.html and it completely fixes the problem.

@markus2610 I did notice that I had to also add apply plugin: 'kotlin-kapt' to the kotlin sample and that generateStubs was not necessary.

You're right that a Kotlin specific example would be useful. At the very least I'll add instructions for what kapt settings to use. I didn't design this for kotlin, and it's unfortunate that fields need to be @AutoModel lateinit var header: HeaderModel_ as it gets a bit verbose compared to java. What I may recommend is not using @AutoModel and just creating the model manually using a string id.

        HeaderModel_()
                .id("header")
                .title(R.string.epoxy)
                .caption(R.string.header_subtitle)
                .addTo(this);


        ButtonModel_()
                .id("add button")
                .text(R.string.button_add)
                .clickListener { model, parentView, clickedView, position -> callbacks.onAddClicked() }
                .addTo(this)

        ButtonModel_()
                .id("clear button")
                .text(R.string.button_clear)
                .clickListener(View.OnClickListener { callbacks.onClearClicked() })
                .addIf(colors.isNotEmpty(), this)

The @AutoModel annotation doesn't give you much over this - it just guarantees a unique id, creates the model, and does some validation that the models are used correctly.

In some ways defining the ids with strings like this is cleaner, since it doesn't split up the model into a field value, and removes the boilerplate of the AutoModel field. The downside is that a string id adds a (very small) chance of id collision, is slightly slower to convert to a long id, and may be a bit confusing for more complicated controllers since you need to manually track the ids and make sure you don't have duplicates (although the runtime validation would throw if you did).

As I've started to integrate Epoxy 2.0 into our app and upgrade adapters to controllers I've noticed that for simpler adapters with just a few @AutoModel fields I actually prefer to remove the @AutoModel usage and define the string id manually

Was this page helpful?
0 / 5 - 0 ratings

Related issues

carlosmuvi picture carlosmuvi  路  3Comments

jamesarich picture jamesarich  路  5Comments

JasonHezz picture JasonHezz  路  4Comments

TonnyL picture TonnyL  路  5Comments

jQrgen picture jQrgen  路  5Comments