Skip to content

@JsonClassDiscriminator not working when isMinifyEnabled = true #3047

@Leronov

Description

@Leronov

Describe the bug
When testing app build before release, I noticed error in deserializing response from server.
I'm not sure about root cause, but seems that minification influence the logic behind @JsonClassDiscriminator.
When custom @JsonClassDiscriminator("entity") set for parent (sealed) class, Json still trying to find sub-class for fields with name "type" in child classes. Basically, in nested classed Json serializer still checking for "type" fields, even thou top hierarchy defines discriminator as "entity".
In debug build - there is no error and everything works.

@Serializable
@JsonClassDiscriminator("entity")
sealed class A

@Serializable
@SerialName("child1")
data class A_Child1(
    type: Any,
)

To Reproduce
In my code (simplified):

@Serializable
data class SyncResponseBody(
    val t: Long,
    val data: List<SyncEntity>,
)

@OptIn(ExperimentalSerializationApi::class)
@JsonClassDiscriminator("entity")
@Serializable
sealed class SyncEntity

@Serializable
@SerialName("category")
data class SyncCategory(
    val id: Long,
    val type: Category.Type, // enum class
) : SyncEntity()

@Serializable
data class Category(...) {
    enum class Type {
        ATYPE, BTYPE, CTYPE,
    }
}

Network module:
@Provides
@Singleton
fun provideJson(): Json = Json {
    encodeDefaults = true
    ignoreUnknownKeys = true
}

With input data:

{"entity":"category","id":737,"type":"ATYPE"}

Everything works fine in debug build.
But when launching app in release variant with isMinifyEnabled = true and
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro") // proguard-rules.pro are empty

There is error:

Serializer for subclass 'ATYPE' is not found in the polymorphic scope of 'B'. // obfuscated B = SyncEntity
Check if class with serial name 'ATYPE' exists and serializer is registered in a corresponding SerializersModule.

To temporary fix the issue, I added descriptor to Json constructor:

@Provides
@Singleton
fun provideJson(): Json = Json {
    encodeDefaults = true
    ignoreUnknownKeys = true
    classDiscriminator = "entity" <! -- added
}

After that - serialization works normal again even in release build.

I did one more experiment. Setup:

@Provides
@Singleton
fun provideJson(): Json = Json {
    encodeDefaults = true
    ignoreUnknownKeys = true
    classDiscriminator = "entity"
}

@OptIn(ExperimentalSerializationApi::class)
@JsonClassDiscriminator("nonsense") <! -- definitely not a discriminator in JSON
@Serializable
sealed class SyncEntity

@Serializable
@SerialName("category")
data class SyncCategory // everything else stay the same

And it works with minifyEnabled = true and release build. Discriminator in @JsonClassDiscriminator simply ignored.
But when I switch to debug build - serialization fails on kotlinx.serialization.json.internal.JsonDecodingException: Class discriminator was missing and no default serializers were registered in the polymorphic scope of 'SyncEntity'.
I truly do not understand why behavior is different in debug and release variants.

Expected behavior
@JsonClassDiscriminator() is working in the same way before and after minification.

Environment

  • Kotlin version: 2.2.0
  • Library version: 1.9.0
  • Imports: org.jetbrains.kotlinx:kotlinx-serialization-core:1.9.0 and org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0
  • Kotlin platforms: JVM, Android
  • Gradle version: Android Gradle Plugin 8.11.1
  • Other relevant context [e.g. OS version, JRE version, ... ] I will provide any additional info on request

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions