38

Can anyone please explain how to migrate to the new kotlin-parcelize?

I tried:

  1. Replace apply plugin: 'kotlin-android-extensions' with apply plugin: 'kotlin-parcelize' in app build.gradle
  2. Replace import kotlinx.android.parcel.Parcelize with import kotlinx.parcelize.Parcelize

The latter one leads to

Class 'ParcelZonedDateTime' is not abstract and does not implement abstract member public abstract fun describeContents(): Int defined in android.os.Parcelable

on e.g. this code:

import androidx.annotation.Keep
import kotlinx.parcelize.Parcelize
import org.threeten.bp.ZonedDateTime

@Keep
@Parcelize
data class ParcelZonedDateTime(var value: ZonedDateTime?) :Parcelable {
    override fun toString(): String {
        return value.toString()
    }
}

So, how to migrate to the new kotlin-parcelize?

Update:

Based on comments: Yes, I am on Kotlin 1.4.20 (which is newer than 1.4.20-M2).Kyzer is right that the error in the IDE (is not abstract and does not implement abstract member public abstract fun describeContents()) can and has to be ignored. Yet I have an issue where I use Generics:

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

sealed class MyDialogEvent {
    @Parcelize
    data class Confirmed<T: Parcelable>(val identity: String, val data: T) : Parcelable
}

The generated code for this is

@kotlin.Metadata(mv = {1, 4, 1}, bv = {1, 0, 3}, k = 3)
public static final class Creator implements android.os.Parcelable.Creator<com.example.stackoverflow.MyDialogEvent.Confirmed> {
    
    public Creator() {
        super();
    }
    
    @org.jetbrains.annotations.NotNull()
    @java.lang.Override()
    public final com.example.stackoverflow.MyDialogEvent.Confirmed<T>[] newArray(int size) {
        return null;
    }
    
    @org.jetbrains.annotations.NotNull()
    @java.lang.Override()
    public final com.example.stackoverflow.MyDialogEvent.Confirmed<T> createFromParcel(@org.jetbrains.annotations.NotNull()
    android.os.Parcel in) {
        return null;
    }
}

and during compilation I get this error for it (line numbers won't match the sample code, but you can easily identify the matching lines by comparing the method names):

MyDialogEvent.java:167: error: non-static type variable T cannot be referenced from a static context
            public final com.example.stackoverflow.MyDialogEvent.Confirmed<T>[] newArray(int size) {
                                                                                       
MyDialogEvent.java:173: error: non-static type variable T cannot be referenced from a static context
            public final com.example.stackoverflow.MyDialogEvent.Confirmed<T> createFromParcel(@org.jetbrains.annotations.NotNull()
stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270
  • Did you also update kotlin to 1.4.20? – Ben P. Nov 24 '20 at 16:56
  • note this plugin is only available starting from version 1.4.20-M2 – Sarah Khan Nov 24 '20 at 17:11
  • What do you mean leads to? If you have updated to 1.4.20. For me, the IDE shows the error but the project builds fine. – Xid Nov 24 '20 at 17:45
  • @KyzerSoze Good hint, thanks for that. Now I have a new issue though. I updated my post accordingly. – stefan.at.kotlin Nov 24 '20 at 18:06
  • @SarahKhan: Thanks, I am on 1.4.20. Would be glad if you could also check my update. – stefan.at.kotlin Nov 24 '20 at 18:06
  • @BenP. Yes, I am on 1.4.20. Would be glad if you could also check my update. – stefan.at.kotlin Nov 24 '20 at 18:07
  • @KyzerSoze: It's an reduced example. There are further classes in the sealed class. One can use sealed classes as some kind of enum of classes. Actually that worked fine until the (attempted) migration to `kotlinx.parcelize`. – stefan.at.kotlin Nov 24 '20 at 18:22
  • 1
    Sorry do not have info on that, but I'm positive generics won't work with the annotation irrespective of package or sealed class due to the fact that methods in the static context in the generated class do not know what generic type T is – Xid Nov 24 '20 at 18:47
  • 3
    Looks like the Parcelize generics error is introduced by Kotlin 1.4.20 itself, not the plugin migration. I still get the same error if you roll back to `kotlin-android-extensions` and keep Kotlin 1.4.20. – dzeikei Nov 30 '20 at 00:42
  • 2
    I'm facing same issue in kotlin 1.4.21 so I roll back my code in to 1.4.10 that's working fine – Saunik Singh Dec 08 '20 at 14:39
  • 1
    I have same issue in my project too. I tried 1.4.21 version but the error is still there. Is anybody find solution for this? This is really annoying. – okarakose Dec 13 '20 at 08:57
  • 1
    I didn't dig further into this, but added a bounty now. Hopefully someone has an answer to this. Or maybe it's a bug and a fix needed? ): – stefan.at.kotlin Dec 13 '20 at 18:04
  • 1
    @stefan.at.wpf regarding your issue with Generics I suggest you post a question on youtrack.jetbrains.com – AndrazP Dec 13 '20 at 19:30
  • I need a fix for this, i am suffering from the same error :( – Ric17101 Dec 15 '20 at 10:07
  • 1
    Still an issue with Kotlin 1.4.30 – Myroslav Feb 12 '21 at 12:04
  • For an updated guide that includes using custom @TypeParcelers, see this post: https://stackoverflow.com/a/71354186/2857200 – RealityExpander Oct 14 '22 at 21:39

6 Answers6

22

That's a bug in kapt and it's reported here. Actually the java code you posted is a stub class which generated by kapt to run annotation processors on it (as you can see, there is no real implementation, just the structure and annotations). So as a workaround you can move the code with @Parcelize annotations to a separate module where you don't have kapt enabled. kotlin-parcelize itself does not use annotation processors to generate code, it uses a compiler plugin to emit the IR directly I believe.

Update: the issue is fixed in kotlin 1.5

esentsov
  • 6,372
  • 21
  • 28
  • How wold we go about moving the code into a separate module? Would this mean the second module would have a separate Gradle file? – 3366784 Feb 03 '21 at 18:55
4

This is work for me, please check the order of lines carefully

plugins {
    id 'kotlin-android'
    id 'kotlin-parcelize'
    id 'kotlin-kapt'    
   }
Leo N
  • 126
  • 2
  • 5
  • I have written an article on how to use custom @TypeParcelers here: https://medium.com/@chrisathanas/how-to-use-parcels-on-kotlin-multiplatform-mobile-kmm-e29590816624 – RealityExpander Oct 15 '22 at 21:32
1

After further checking, I think Parcelable generic type with Parcel constructing fails to compile because T class can not be determined generically based from this reference.

enter image description here

Perhaps an enum could be the last resort.

Ric17101
  • 1,063
  • 10
  • 24
0

I use the Kotlin version 1.4.10:

implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.10"

but in my module, only apply

id 'kotlin-android'
id 'kotlin-android-extensions'

and it work for me.

There is all my plugins apply in my module:

plugins {
    id 'com.android.library'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
    id 'androidx.navigation.safeargs.kotlin'
}
  • And you use a `kotlinx.android.parcel.Parcelize` implementation. See also https://stackoverflow.com/questions/64981310/plugin-kotlin-parcelize-not-found. – CoolMind Oct 12 '21 at 20:33
  • Check out this article to be able to use a @TypeParceler for non-primitive classes. https://medium.com/@chrisathanas/how-to-use-parcels-on-kotlin-multiplatform-mobile-kmm-e29590816624 – RealityExpander Oct 15 '22 at 01:45
-1

Answer for original question:

If you see this error in Android Studio:

Class 'ClassName' is not abstract and does not implement abstract member public abstract fun describeContents(): Int defined in android.os.Parcelable

Make sure that you have updated both Kotlin dependency and Android Studio Kotlin plugin to 1.4.20 or later. enter image description here After updating the plugin make sure to File -> Invalidate Caches / Restart. That worked for me.

AndrazP
  • 217
  • 4
  • 11
  • 4
    Unfortunatelly it didn't work for me. I'm targeting 1.4.30 in both - project and as AS plugin, AS ver. 4.1.2. After invalidating caches, still the same issue. – Myroslav Feb 12 '21 at 12:15
-4

change this line: import kotlinx.parcelize.Parcelize to: import kotlinx.android.parcel.Parcelize