fieldFromJson function
Converts a Proto3 JSON value back to its protobuf field representation.
Type-specific conversions:
TYPE_INT64,TYPE_UINT64,TYPE_SINT64,TYPE_SFIXED64,TYPE_FIXED64: string -> int.TYPE_BYTES: base64 string ->List<int>.TYPE_FLOAT,TYPE_DOUBLE: "NaN"/"Infinity"/"-Infinity" -> double.TYPE_ENUM: string name -> ordinal using the reverseenumValuesmap.TYPE_MESSAGE: recursively unmarshaled usingmessageDescriptor.TYPE_INT32,TYPE_UINT32, etc.: numeric coercion from JSON number.TYPE_BOOL: passed through.TYPE_STRING: passed through.
enumValues maps ordinal -> name; this function reverses it to look up
by name. messageDescriptor is the nested field descriptor list for
TYPE_MESSAGE fields.
Implementation
Object? fieldFromJson(
Object? jsonValue,
String type, {
Map<int, String>? enumValues,
List<Map<String, Object?>>? messageDescriptor,
Map<String, String>? features,
}) {
if (jsonValue == null) return null;
switch (type) {
// 64-bit integers: JSON string -> int.
case 'TYPE_INT64':
case 'TYPE_UINT64':
case 'TYPE_SINT64':
case 'TYPE_SFIXED64':
case 'TYPE_FIXED64':
if (jsonValue is String) {
return int.parse(jsonValue);
}
if (jsonValue is num) {
return jsonValue.toInt();
}
return jsonValue;
// bytes: base64 string -> List<int>.
case 'TYPE_BYTES':
if (jsonValue is String) {
return base64.decode(jsonValue);
}
return jsonValue;
// float / double: handle special string literals.
case 'TYPE_FLOAT':
case 'TYPE_DOUBLE':
if (jsonValue is String) {
switch (jsonValue) {
case 'NaN':
return double.nan;
case 'Infinity':
return double.infinity;
case '-Infinity':
return double.negativeInfinity;
default:
return double.parse(jsonValue);
}
}
if (jsonValue is int) {
return jsonValue.toDouble();
}
return jsonValue;
// enum: string name -> ordinal.
case 'TYPE_ENUM':
if (jsonValue is String && enumValues != null) {
// Reverse lookup: find the ordinal for this name.
for (final entry in enumValues.entries) {
if (entry.value == jsonValue) {
return entry.key;
}
}
// If the string is a numeric literal, parse it.
final numeric = int.tryParse(jsonValue);
if (numeric != null) return numeric;
// Unknown enum name. Proto3 JSON (json_format = ALLOW, the editions
// default) requires a known name or a numeric literal — reject. Under
// LEGACY_BEST_EFFORT (proto2) or when features are absent, tolerate it
// by passing the raw string through (legacy best-effort behavior).
if (features != null && jsonFormatIsAllow(features)) {
throw FormatException(
'Unknown enum value "$jsonValue" (json_format=ALLOW requires a '
'known name or numeric literal)',
);
}
return jsonValue;
}
if (jsonValue is num) {
return jsonValue.toInt();
}
return jsonValue;
// message: recursive unmarshal.
case 'TYPE_MESSAGE':
if (messageDescriptor != null && jsonValue is Map) {
final stringMap = <String, Object?>{};
for (final entry in jsonValue.entries) {
stringMap[entry.key.toString()] = entry.value;
}
return _unmarshalFromMap(stringMap, messageDescriptor);
}
return jsonValue;
// 32-bit integers and fixed-width 32-bit: coerce from JSON number.
case 'TYPE_INT32':
case 'TYPE_UINT32':
case 'TYPE_SINT32':
case 'TYPE_FIXED32':
case 'TYPE_SFIXED32':
if (jsonValue is String) {
return int.parse(jsonValue);
}
if (jsonValue is num) {
return jsonValue.toInt();
}
return jsonValue;
case 'TYPE_BOOL':
if (jsonValue is bool) return jsonValue;
if (jsonValue is String) return jsonValue == 'true';
return jsonValue;
case 'TYPE_STRING':
final s = jsonValue is String ? jsonValue : jsonValue.toString();
_verifyUtf8IfRequired(s, features);
return s;
default:
return jsonValue;
}
}