Kotlin annotation processing ignores items with similar names
Asked Answered
P

3

9

I recently converted the majority of my project to kotlin. Now I encounter several unusual errors that all seem to relate to annotation libraries. Needless to say, it didn't happen in Java.

I'll describe the cases - one in Dagger and one in Butterknife.

1. When having 2 @Provides methods in different models with the same name. For example in file "FooProvider.kt" having a "provideFooOrBar" method

@Module
class FooProvider(private val view: FooActivity) {
    ... 
    @Provides @FooScope fun provideView() = view
    @Provides @FooScope fun provideFooOrBar() = Foo()
}

And having another file "BarProvider.kt" with the same method name

@Module
class BarProvider(private val view: BarActivity) {
    ...
    @Provides @BarScope fun provideView() = view
    @Provides @BarScope fun provideFooOrBar() = Bar()
}

In this case, Dagger fails to generate some factory libraries and I get the following compilation error: Error:(27, 32) error: cannot find symbol class FooProvider_ProvideFooOrBarFactory

A sample project reproducing the issue can be found at https://github.com/maxandron/DaggerIssue325

2. This is an issue when using Butterknife. When having two @Bind annotated variables in two different classes - One of them just fails to initialize at runtime without any compilation error!

For example if I have:

class FooActivity {
    @Bind(R.id.foo) lateinit var mFoo: View
}
class NotFooActivity {
    @Bind(R.id.not_foo) lateinit var mFoo: View
}

Then one of them (or both?) will just fail to initialize without any error. Causing a kotlin.UninitializedPropertyAccessException: lateinit property mFoo has not been initialized exception to be thrown when the field is accessed.


Is it something I'm doing wrong in configuring Kotlin or is it a kotlin bug?

Thank you in advance! Ron

Protomartyr answered 25/2, 2016 at 17:7 Comment(20)
These two questions look unrelated to me, please don't ask two different questions in a single SO post next timeLaurice
I posted them in the same question because the do seem related. I don't think it's a dagger or butterknife bug - I think it's a kotlin bug. I'm not trying to find solutions for the error - I know them, I want to understand the causeProtomartyr
They likely are two different issues. One for the methods, and another for where you placed the annotation on a property. Read about Annotation Use-Site targets and see if that helps to resolve the 2nd one kotlinlang.org/docs/reference/… along with maybe making it a JvmField dpending on what butterknife wants kotlinlang.org/docs/reference/…Oberland
Did you look at KnotterKnife? github.com/JakeWharton/kotterknife which is like Butterknife but written for KotlinOberland
Also there are Kotlin specific dependency injection libraries that understand Kotlin better than something from Java will. For example, Java can't see nullability, and cannot construct a Kotlin object while using default parameters (unless you use @JvmOverloads), cannot see parameter names. So a primitive system is trying to use a more advanced without understanding it. Injekt and Kodein might be useful.Oberland
so as @AlexanderUdalov says, you likely have two different issues completely in one SO question.Oberland
For your first problem, it seems odd that this would be a Kotlin issue. They are normal classes with normal methods and the byte code would be identical to Java doing the same. Do the classes need to be extendable? (i.e. open class) instead of final? I would think it would fail in Java, this exact case because there isn't a difference. Your issue with properties COULD be related to the target of the annotation, but this other case I think is you or dagger bugOberland
I see... should I split this question into two somehow then? It just seems very unlikely encountering two issues that seem related (both because of similar variable/method names) one after another.. Also, I tried reproducing the first issue in Java and was not successful, it is definitely a kotlin only issueProtomartyr
I don't see how they can be related, checking your test project now.Oberland
what is the java equivalent, is it in your test project?Oberland
It is, you can find it in this commit: github.com/maxandron/DaggerIssue325/tree/… Thanks for your help Jayson!Protomartyr
The issue could be order of compilation, are you using Kapt?Oberland
your project files aren't usable, for some reason they have hard coded paths to modules.Oberland
I am. I'll try to commit it againProtomartyr
You have source sets for src/main/kotlin in your gradle but then put your source in src/main/java, is that an issue?Oberland
No, it shouldn't be - It just adds the sources. In my other project I have some sources in /java and some in /kotlinProtomartyr
So is your error from gradle command-line build or IDE build?Oberland
from IDE build (android studio)Protomartyr
I think I removed all files that might contain hard coded paths from the repositoryProtomartyr
I can't get android studio to load your project well enough to do anything, I think an android person can help more, especially as they use Kapt and related tools more. Could be a bug somewhere in annotation processing, how names are mangled, etc. You'll need to narrow it down more, maybe enter a bug in YouTrack (youtrack.jetbrains.com), or ask people in the #android channel on Kotlin slack since they may have encountered this or will tell you what they use instead. kotlinlang.org/community.htmlOberland
P
1

It turned out to be a bug with kapt. I posted an issue on Kotlin's bug tracker and the issue is now marked as fixed.

This solution was merged

Should be resolved in Kotlin version 1.0.2

Protomartyr answered 31/3, 2016 at 16:9 Comment(0)
I
3

I was having this issue, so I started to investigate and it's caused because Kapt is only checking the method name when comparing them, and they are added in a set, thus duplicates are not allowed. The same happens for annotated fields, so currently you can have one method/field name per annotation.

I added the class name to the equals method and the annotations were properly handled now, but the tests broke and I don't know how they work, so I hope someone knows how to fix this.

Intensify answered 20/3, 2016 at 18:29 Comment(3)
Nice find! I see here that fields are also only checked by name, which explains butterknife. In any case, they are away of the problem and fixing it - I will post here when it is resolvedProtomartyr
Also means I was right to post those two problems in the same questions (And being right is always good :))Protomartyr
I just found a pull request already open github.com/JetBrains/kotlin/pull/822Intensify
P
1

It turned out to be a bug with kapt. I posted an issue on Kotlin's bug tracker and the issue is now marked as fixed.

This solution was merged

Should be resolved in Kotlin version 1.0.2

Protomartyr answered 31/3, 2016 at 16:9 Comment(0)
M
0

So to somewhat answer the kotlin.UninitializedPropertyAccessException: lateinit issue, I was running into the exact same thing in my project. What I did which "solved the issue" for me was to remove Butterknife from the offending class, in this case it was just a viewHolder for my new expandable RecyclerView, and then run the app again.

Running the app, after switching all my @Bind(R.id.my_view_id) to the "old school" findViewById(R.id.my_view_id) as MyViewType worked, but then subsequently afterwards I switched the same class back to Butterknife and the UninitializedPropertyAccessException went away, and it seems like it won't come back unless something in the class changes, then you'll have to repeat this process again.

My suspicion here is that this has something to do with Kotlin not supporting incremental compilation, and somehow by changing the auto-generated code it was forced to recompile. But I could be way off here, just thought I'd share my experience.

Melanesian answered 28/2, 2016 at 23:7 Comment(1)
Thanks for your effort, obviously I always have the ability to switch off libraries I used before. But I don't want to. The porpuse of using Kotlin is for it to be completely interoperable with Java. In any case, after researching it, and posting a bug on the tracker. It is definetlly a bug with kapt. I will update here when it is fixed. Right now I switch butterknife to 'kotlin android extensions' pluginProtomartyr

© 2022 - 2024 — McMap. All rights reserved.