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

maxandron
  • 1,650
  • 2
  • 12
  • 16
  • These two questions look unrelated to me, please don't ask two different questions in a single SO post next time – Alexander Udalov Feb 25 '16 at 17:28
  • 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 cause – maxandron Feb 25 '16 at 17:30
  • 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 https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets along with maybe making it a JvmField dpending on what butterknife wants https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields – Jayson Minard Feb 25 '16 at 17:37
  • Did you look at KnotterKnife? https://github.com/JakeWharton/kotterknife which is like Butterknife but written for Kotlin – Jayson Minard Feb 25 '16 at 17:37
  • 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. – Jayson Minard Feb 25 '16 at 17:39
  • so as @AlexanderUdalov says, you likely have two different issues completely in one SO question. – Jayson Minard Feb 25 '16 at 17:40
  • 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 bug – Jayson Minard Feb 25 '16 at 17:43
  • 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 issue – maxandron Feb 25 '16 at 17:49
  • I don't see how they can be related, checking your test project now. – Jayson Minard Feb 25 '16 at 17:51
  • what is the java equivalent, is it in your test project? – Jayson Minard Feb 25 '16 at 17:52
  • It is, you can find it in this commit: https://github.com/maxandron/DaggerIssue325/tree/422f45db6ce19c315fd6b9d749c11cb3a748fee1 Thanks for your help Jayson! – maxandron Feb 25 '16 at 17:53
  • The issue could be order of compilation, are you using Kapt? – Jayson Minard Feb 25 '16 at 17:56
  • your project files aren't usable, for some reason they have hard coded paths to modules. – Jayson Minard Feb 25 '16 at 17:56
  • I am. I'll try to commit it again – maxandron Feb 25 '16 at 17:57
  • You have source sets for `src/main/kotlin` in your gradle but then put your source in `src/main/java`, is that an issue? – Jayson Minard Feb 25 '16 at 17:59
  • No, it shouldn't be - It just adds the sources. In my other project I have some sources in /java and some in /kotlin – maxandron Feb 25 '16 at 18:02
  • So is your error from gradle command-line build or IDE build? – Jayson Minard Feb 25 '16 at 18:04
  • from IDE build (android studio) – maxandron Feb 25 '16 at 18:05
  • I think I removed all files that might contain hard coded paths from the repository – maxandron Feb 25 '16 at 18:08
  • 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.html – Jayson Minard Feb 25 '16 at 18:26

3 Answers3

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.

inorichi
  • 406
  • 7
  • 12
  • Nice find! I see here that fields are also only [checked by name](https://github.com/JetBrains/kotlin/blob/master/libraries/tools/kotlin-annotation-processing/src/main/kotlin/org/jetbrains/kotlin/annotation/AnnotationProcessorWrapper.kt#L49), which explains butterknife. In any case, they are away of the problem and fixing it - I will post here when it is resolved – maxandron Mar 21 '16 at 10:00
  • Also means I was right to post those two problems in the same questions (And being right is always good :)) – maxandron Mar 21 '16 at 10:01
  • 1
    I just found a pull request already open https://github.com/JetBrains/kotlin/pull/822 – inorichi Mar 25 '16 at 01:57
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

maxandron
  • 1,650
  • 2
  • 12
  • 16
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.

Derek
  • 632
  • 2
  • 11
  • 29
  • 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' plugin – maxandron Feb 28 '16 at 23:29