Skip to content

JSON serialisation throws for repeated enum with unknown constants. #3430

@oldergod

Description

@oldergod

Originally reported by @jguze

Assume I have a proto enum and another message with the repeated enum with a few values like this:

enum ExampleEnum {
  UNSPECIFIED = 0;
  TEST = 1;
}

message Container {
  repeated ExampleEnum examples = 0; 
}

This generates some kotlin code that specifically has this line:
public val examples: List<ExampleEnum> = immutableCopyOf("examples", examples)
Then let's say I introduce a new enum value, such as NEW_VALUE = 2.
For clients who are not upgraded, they'll see this value they don't recognise when decoding, and evaluate it to null. The problem I'm running into is that the immutableCopyOf will throw an exception if it sees null:

fun <T> immutableCopyOf(name: String, list: List<T>): List<T> {
  @Suppress("NAME_SHADOWING")
  var list = list
  if (list is MutableOnWriteList<*>) {
    list = (list as MutableOnWriteList<T>).mutableList
  }
  if (list === emptyList<T>() || list is ImmutableList<*>) {
    return list
  }
  val result = ImmutableList(list)
  // Check after the list has been copied to defend against races.
  require(null !in result) { "$name.contains(null)" }
  @Suppress("UNCHECKED_CAST")
  return result as List<T>
}

Specifically, the line require(null !in result) { "$name.contains(null)" }
This shows up an IllegalArgumentException
Is there a workaround for this? Ideally I'd just have the any unrecognised values evaluate to UNSPECIFIED rather than null.
What is happening is that I have a list of enums coming back via JSON. One of the enum values in the response is something the client doesn't know about yet.
In the MessageJsonAdapter in fromJson, we attempt to parse out all the fields into their respective classes. The adapter being used for our list of enums is the ListJsonAdapter from the MoshiJsonIntegration. Unfortunately, this adapter will generate a list with null inside it if it doesn't recognise the enum.
It will then attempt to build the object here, which will ultimately throw the error I mentioned above.

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