proguardkotlinx.serialization

How to make proguard keep kotlinx serializers for objects?


i have a kotlin class and an object


@Serializable
@SerialName("Cl")
class Cl(...)

@Serializable
@SerialName("Obj")
object Obj

and my proguard is configured like this

-keepclassmembers class kotlinx.serialization.json.** {
    *** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
    kotlinx.serialization.KSerializer serializer(...);
}
-keepclasseswithmembers class .** {
    kotlinx.serialization.KSerializer serializer(...);
}

-keep,includedescriptorclasses class my.package.**$$serializer { *; }

but, while the serializer of the class is kept, the serializer of the object is not. here is the mapping of the class:

Cl -> Cl:
...
    ...
    67:67:void <init>(... ,kotlinx.serialization.internal.SerializationConstructorMarker) -> <init>
    70:75:void <init>(...) -> <init>
    67:67:void write$Self(Cl,kotlinx.serialization.encoding.CompositeEncoder,kotlinx.serialization.descriptors.SerialDescriptor) -> e
Cl$$serializer -> Cl$$serializer:
...
    67:75:void <clinit>() -> <clinit>
    67:67:void <init>() -> <init>
    67:67:kotlinx.serialization.KSerializer[] childSerializers() -> childSerializers
    67:67:Cl deserialize(kotlinx.serialization.encoding.Decoder) -> deserialize
    67:67:java.lang.Object deserialize(kotlinx.serialization.encoding.Decoder) -> deserialize
    67:67:void serialize(kotlinx.serialization.encoding.Encoder,Cl) -> serialize
    67:67:void serialize(kotlinx.serialization.encoding.Encoder,java.lang.Object) -> serialize
    67:67:kotlinx.serialization.KSerializer[] typeParametersSerializers() -> typeParametersSerializers
Cl$Companion -> Cl$Companion:
...
    67:67:void <init>() -> <init>
    67:67:kotlinx.serialization.KSerializer serializer() -> serializer

and here is the mapping of the object:

Obj -> Obj:
...
    Obj INSTANCE -> n
    kotlin.Lazy $cachedSerializer$delegate -> o
    ...
    47:47:kotlin.Lazy get$cachedSerializer$delegate() -> e
    47:47:kotlinx.serialization.KSerializer serializer() -> serializer
Obj$$cachedSerializer$delegate$1 -> Obj$a:
...
    Obj$$cachedSerializer$delegate$1 INSTANCE -> l
    47:47:kotlinx.serialization.KSerializer invoke() -> a
    47:47:java.lang.Object invoke() -> m
...

this obfuscation causes a crash (only when obfuscated, only for object) when using:

polymorphic(...) {
  subclass(Obj::class)
}

Serializer for class 'Obj' is not found. Mark the class as @Serializable or provide the serializer explicitly.

How can i tell Proguard to keep the serializer for objects?


Solution

  • There is documentation available on how to configure ProGuard, which does not seem to match the configuration you are using.

    Use that and you should be good to go.

    Purely informational, since the above already answers your question: serializer lookup at runtime for object is different and happens through INSTANCE. The relevant part from the docs.

    # Keep `INSTANCE.serializer()` of serializable objects.
    -if @kotlinx.serialization.Serializable class ** {
        public static ** INSTANCE;
    }
    -keepclassmembers class <1> {
        public static <1> INSTANCE;
        kotlinx.serialization.KSerializer serializer(...);
    }