What I'm trying to achieve is a simple pattern that I'm using in Java and should be do-able in Kotlin according to the documentation. I just want to declare an enum class with a couple of constant definitions that implement the same abstract functions.
My problem is that I cannot manage to make my code compile. I always get the same error:
modifier abstract not allowed here
Here is the code:
enum class Program {
HOME {
override fun readableName(context: Context): String {
return context.getString(R.string.program_home)
}
},
WEEKEND {
override fun readableName(context: Context): String {
return context.getString(R.string.program_weekend)
}
},
SHOPPING {
override fun readableName(context: Context): String {
return context.getString(R.string.program_shopping)
}
};
abstract fun readableName(context: Context): String
}
I have even tried with the sample code from the documentation and yet even this does not compile.
Could anyone have an idea about this odd issue? Btw I'm currently using Kotlin 1.0.6.
I just tried your code and it's compiled normally with Kotlin plugin 1.0.6-release-Studio2.2-1
Maybe you can just try to update AndroidStudio/Kotlin plugin ?
Alright... so I found out where the issue was and it was not what I expected to be. #Kirill Rakhman was right, there was nothing wrong with the enum code. I had an issue with kapt that was unable for some reason to generate my project annotations. More specifically I was using - what I missed as experimental - the newly available gradle kapt plugin documented here.
I rolled back to the previous kapt settings by replacing
apply plugin: 'kotlin-kapt'
by
kapt {
generateStubs = true
}
And it worked! Not sure why the compilation failed while declaring my enum though.
Thanks a lot for those who took time to look into it and if you have any idea why the experimental kapt plugin was not behaving as expected feel free to comment this answer, I would gladly want to know what happened :)
Related
This is an simplified example of what I try to do but still failed
class Definition {
#Target(AnnotationTarget.TYPE, AnnotationTarget.VALUE_PARAMETER)
#IntDef(View.VISIBLE, View.INVISIBLE, View.GONE)
//only 0,4,8 are allowed
#Retention(AnnotationRetention.SOURCE)
annotation class Visibility
}
fun isVisibleView(#Definition.Visibility visibility: Int, viewList: ArrayList<View>, ) {
for (view in viewList) {
view.visibility = visibility
}
}
//I want the ide to SHOW ERROR here since 2 is not in 0,4,8 (show before compile)
isVisibleView(2, visibleItems)
I think this question is about IDE config or Kotlin syntax
In short Enum is enough.
IntDef is android specific so you'd have to find an Android rule for IntelliJ to analyze those annotations.
Even you can make it work it only on java not Kotlin.
It seems like the warning will be generated by lint but only if you write the annotation in Java, not Kotlin
As state in this issue https://youtrack.jetbrains.com/issue/KTIJ-18693
https://developer.android.com/studio/write/annotations?fbclid=IwAR2duPFqsMx1VPDlK0nyt8-mAKJyLw_WAjY5GQMIHH__-FMpRV9SNJpqY6k
Credit: Anton Malinsky
This is with implementation 'org.json:json:20180813'
So I have a User class that allows itself to be translated to a json string for persistence:
data class User(override val name:String, override val creds:ICredentials) : IUser, isEncodable<IUser>{
override val isLoggedIn by lazy { creds is Credentials.Valid }
override fun encode():String{
val credsEncoding = creds.encode()
return JSONStringer().withObject { it
.key("type").value(this::class.java.name)
.key("name").value(name)
.key("creds").value(credsEncoding)
}.toString()
}
}
where withObject is an extension function:
fun JSONWriter.withObject(content:(JSONWriter)->JSONWriter) = content(`object`() as JSONWriter).endObject()
This seems to compile and work perfectly fine.
However, AndroidStudio marks it red and claims
Unresolved reference
None of the following candidates is applicable because of receiver type mismatch
public fun JSONWriter.withObject(content:(JSONWriter)->JSONWriter):JSONWriter! defined in [...]`
If I try to "cheat" and write it as
(JSONStringer() as JSONWriter).withObject { it
...
}
the error becomes a warning that
This cast can never succeed.
But apparently, it does.
Why is that? And how do I get rid of this "error"?
This is with implementation 'org.json:json:20180813'
That's unlikely to work well.
Why is that?
For the past 11 years, Android has a copy of org.json classes in the Android SDK. This includes JSONStringer. You can't have two classes with the same fully-qualified name, and the firmware always wins. Your copy of the conflicting class will not be used, with the firmware one used instead. And the firmware's API has not changed much in those past 11 years.
And how do I get rid of this "error"?
Remove implementation 'org.json:json:20180813'. Either:
Use the Android SDK's built-in org.json classes, or
Use the Android SDK's JsonReader and JsonWriter classes, or
Use a different JSON parser (e.g., Gson, Jackson, Moshi)
I cannot compile anymore after the update to Kotlin 1.3.0 (works in 1.2.71) when trying to use by lazy and object. This seems to happen only on my project. A demo-project is working fine.
I want to add an interface to a given class and lazy-load its values.
I've created a small example which is not working in my project but working fine in any other:
open class Foo
interface Bar {
val lazyLoadedString : String
}
class Test {
private val foo by lazy {
object : Foo(), Bar {
override val lazyLoadedString = "Demo"
}
}
}
As soon as I combine object and by lazy, it cannot compile anymore and shows the following error. Using each one alone works.
Test.java:9: error: cannot find symbol
private final my.package.Test$foo$2$1 getFoo()
symbol: class Test$foo$2$1
location: package my.package
When looking closer, you'll see that the generated java file shows this error and not the kotlin-code.
Any ideas on this?
It looks like kapt is broken in Kotlin 1.3.0 for this particular kind of code.
In the code above, it was the annotation processor registered by Realm that triggered it, but any other annotation processor would have resulted in the same error.
The issue is being tracked here: https://youtrack.jetbrains.net/issue/KT-28053
In my Kotlin Multiplatform project, I'm trying to access Kotlin types defined in kotlin-stdlib from Swift.
TL;DR: StdLib types/methods seem not to result in header definitions, I'd like a solution that doesn't involve writing lots of boilerplate code
My scenario
I have an interface defined in Kotlin ...
interface MyKotlinInterface {
fun run() : Sequence<String>
}
... and implemented this interface in Swift ...
class MySwiftClass : MyKotlinInterface {
func run() -> KotlinSequence {
// return sequenceOf("foo")
}
}
... there I'm trying to create a Sequence but there are no methods from the kotlin.sequences package available (e.g. generateSequence).
Is it actually possible to access Kotlin framework types or methods beyond what I define in my code -- if yes, how? Furthermore, how can this be achieved without writing boilerplate code?
Further details
Having a look into the generated Objective-C header file, I see definitions for my class (obviously) and basic Kotlin types. What's missing is basically everything from the standard library functionality (I care for everything Sequence-related).
My build.gradle.kts looks like:
plugins {
kotlin("multiplatform") version "1.3.0"
}
kotlin {
targets { /* ... */ }
sourceSets {
getByName("commonMain") {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib-common")
}
}
// ...
getByName("iosMain") {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib")
}
}
}
}
Having the kotlin-stdlib defined as a dependency for the iOS target, I would expect those to become actually available from Swift.
Minimal working example
https://github.com/panzerfahrer/so-mwe-kotlin-mpp-swift
Current solution approach
The only solution I came up with, is writing the desired function for the iOS target:
fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?): kotlin.sequences.Sequence<T> = kotlin.sequences.generateSequence(nextFunction)
This works ok-ish but is highly unsatisfying as it requires lots of boilerplate code. Additionally, extension functions cannot be made available this way and would require more boilerplate code or even rewriting parts of the standard library.
Desired solution
I like to avoid writing boilerplate code as much as possible. What I actually only care about, is to have (in my case) Sequence fully accessible from Swift. My feeling is, it would be sufficient to make the compiler generate selected or all header definitions for the standard library functionality.
Do you really need lazy computation (aka Sequence) in your Kotlin code?
If no, I would recommend using List<T> instead (and it maps to Swift directly).
For Sequence implementation, a workaround could be to export a factory function from your Kotlin library, e.g. you may declare a function like
fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?)
= kotlin.sequences.generateSequence(nextFunction)
You may select any other factory function for Sequence, that matches your use-case.
In general, there are too many functions in the Kotlin standard library. Exporting them all to Swift will create too many useless symbols in the binary and increase the compilation time.
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
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.
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
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.