-
Notifications
You must be signed in to change notification settings - Fork 602
Open
Description
Problem Summary
When deserializing JSON containing a repeated enum field (List<SomeEnum>) with unknown enum values, Wire's GSON integration crashes with IllegalArgumentException: field_name.contains(null) because:
EnumJsonFormatter.fromString()returnsnullfor unknown enum valuesListJsonAdapteradds thesenullvalues to the result list- Wire's
immutableCopyOf()rejects lists containingnull
Affected Code Paths
1. EnumJsonFormatter.kt (wire-runtime)
override fun fromString(value: String): E? {
return stringToValue[value]
// If the constant is unknown to our runtime, we return a `Unrecognized` instance if it has
// been generated.
?: unrecognizedClassConstructor?.newInstance(value.toInt())
}When there's no Unrecognized class (standard enum generation), this returns null for unknown values.
2. GsonJsonIntegration.kt (wire-gson-support)
private class ListJsonAdapter<T>(
private val single: TypeAdapter<T>,
) : TypeAdapter<List<T?>>() {
override fun read(reader: JsonReader): List<T?> {
val result = mutableListOf<T?>()
reader.beginArray()
while (reader.hasNext()) {
result.add(single.read(reader)) // Adds null from EnumJsonFormatter
}
reader.endArray()
return result // List contains nulls!
}
}3. Internal.kt (wire-runtime)
fun <T> immutableCopyOf(name: String, list: List<T>): List<T> {
if (list.contains(null)) {
throw IllegalArgumentException("$name.contains(null)") // CRASH!
}
// ...
}Reproduction
Given this proto:
enum HotelPageBlock {
UNKNOWN = 0;
MAP_BLOCK = 1;
BENEFITS_BLOCK = 2;
}
message RubiricHotelPageBlockOrder {
repeated HotelPageBlock hotel_page_blocks = 1;
}And this JSON with an unknown enum value (e.g., server added NEW_BLOCK = 17):
{
"hotelPageBlocks": ["MAP_BLOCK", "NEW_BLOCK", "BENEFITS_BLOCK"]
}Deserialization crashes:
java.lang.IllegalArgumentException: hotel_page_blocks.contains(null)
at com.squareup.wire.internal.Internal__InternalKt.immutableCopyOf(Internal.kt:72)
at proto.hotels.v1.RubiricHotelPageBlockOrder.<init>(RubiricHotelPageBlockOrder.kt:48)
Expected Behavior
Wire should handle unknown enum values in repeated fields gracefully, either by:
- Filtering out unknown values (like proto binary decoding does - stores in
unknownFields) - Using the default enum value (first constant, typically
UNKNOWN = 0) - Providing a configuration option to choose the behavior
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels