I declared protobuf message like this.
message request {
repeated sint32 Ids = 1;
}
and I tried to save this message in the form of json in DB. Serialize worked well but when I deserialize it, 'Ids' field is empty. What am I missing?
var requrest = new Request;
foreach(Int16 Id in Ids) {
request.Ids.Add(Id);
}
string SerializedReq = JsonSerializer.Serialize(request); // "{\"Ids\":[10,28]}"
var DeserializedReq = JsonSerializer.Deserialize<Request>(SerializedReq); // {{}} empty
You should implement a Converter and a ConverterFactory like this:
public class RepeatedFieldConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
if (typeToConvert.GetGenericTypeDefinition() != typeof(RepeatedField<>))
{
return false;
}
return true;
}
public override JsonConverter CreateConverter(
Type type,
JsonSerializerOptions options)
{
Type itemType = type.GetGenericArguments()[0];
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(RepeatedFieldConverter<>).MakeGenericType(
new Type[] { itemType }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: new object[] { options },
culture: null)!;
return converter;
}
private class RepeatedFieldConverter<TItem> :
JsonConverter<RepeatedField<TItem>>
{
private readonly JsonConverter<TItem> _valueConverter;
private readonly Type _valueType;
public RepeatedFieldConverter(JsonSerializerOptions options)
{
_valueConverter = (JsonConverter<TItem>)options
.GetConverter(typeof(TItem));
_valueType = typeof(TItem);
}
public override RepeatedField<TItem> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
{
throw new JsonException();
}
var repeatedField = new RepeatedField<TItem>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndArray)
{
return repeatedField;
}
TItem value = _valueConverter.Read(ref reader, _valueType, options)!;
repeatedField.Add(value);
}
throw new JsonException();
}
public override void Write(
Utf8JsonWriter writer,
RepeatedField<TItem> repatedField,
JsonSerializerOptions options)
{
writer.WriteStartArray();
foreach (TItem value in repatedField)
{
_valueConverter.Write(writer, value, options);
}
writer.WriteEndArray();
}
}
}
And use it like this:
var persons = new RepeatedField<Person>();
persons.Add(new Person()
{
Name = "Joe"
});
//Converter for serializing is not mandatory, James Newton-King supports this out of the box ;-)
var jsonPersons = System.Text.Json.JsonSerializer.Serialize(persons, new System.Text.Json.JsonSerializerOptions()
{
Converters = { new RepeatedFieldConverterFactory() }
});
var deserializedPersons = System.Text.Json.JsonSerializer.Deserialize<RepeatedField<Person>>(jsonPersons, new System.Text.Json.JsonSerializerOptions()
{
Converters = { new RepeatedFieldConverterFactory() }
});