diff options
author | Jon Skeet <jonskeet@google.com> | 2015-07-31 15:07:50 +0100 |
---|---|---|
committer | Jon Skeet <jonskeet@google.com> | 2015-08-03 09:32:36 +0100 |
commit | e7caf15577e4fc8a024403bd8586041742d9e266 (patch) | |
tree | bad3eece629af358c2e808e26073c301524aa312 /csharp/src/Google.Protobuf | |
parent | 115e6c735ec561d5260c134fa74ee0d5121a441b (diff) | |
download | protobuf-e7caf15577e4fc8a024403bd8586041742d9e266.tar.gz protobuf-e7caf15577e4fc8a024403bd8586041742d9e266.tar.bz2 protobuf-e7caf15577e4fc8a024403bd8586041742d9e266.zip |
Initial pass at formatting Struct as JSON.
This seems remarkably little code, but it appears to work. I can add tests for invalid structs at some point, once the general approach is approved.
Diffstat (limited to 'csharp/src/Google.Protobuf')
-rw-r--r-- | csharp/src/Google.Protobuf/JsonFormatter.cs | 84 |
1 files changed, 81 insertions, 3 deletions
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index 099fb6a1..3b25beb6 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -380,23 +380,44 @@ namespace Google.Protobuf /// </summary> private void WriteWellKnownTypeValue(StringBuilder builder, MessageDescriptor descriptor, object value, bool inField) { + if (value == null) + { + WriteNull(builder); + return; + } // For wrapper types, the value will be the (possibly boxed) "native" value, // so we can write it as if we were unconditionally writing the Value field for the wrapper type. - if (descriptor.File == Int32Value.Descriptor.File && value != null) + if (descriptor.File == Int32Value.Descriptor.File) { WriteSingleValue(builder, descriptor.FindFieldByNumber(1), value); return; } - if (descriptor.FullName == Timestamp.Descriptor.FullName && value != null) + if (descriptor.FullName == Timestamp.Descriptor.FullName) { MaybeWrapInString(builder, value, WriteTimestamp, inField); return; } - if (descriptor.FullName == Duration.Descriptor.FullName && value != null) + if (descriptor.FullName == Duration.Descriptor.FullName) { MaybeWrapInString(builder, value, WriteDuration, inField); return; } + if (descriptor.FullName == Struct.Descriptor.FullName) + { + WriteStruct(builder, (IMessage) value); + return; + } + if (descriptor.FullName == ListValue.Descriptor.FullName) + { + var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor; + WriteList(builder, fieldAccessor, (IList) fieldAccessor.GetValue(value)); + return; + } + if (descriptor.FullName == Value.Descriptor.FullName) + { + WriteStructFieldValue(builder, (IMessage) value); + return; + } WriteMessage(builder, (IMessage) value); } @@ -483,6 +504,63 @@ namespace Google.Protobuf } } + private void WriteStruct(StringBuilder builder, IMessage message) + { + builder.Append("{ "); + IDictionary fields = (IDictionary) message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message); + bool first = true; + foreach (DictionaryEntry entry in fields) + { + string key = (string) entry.Key; + IMessage value = (IMessage) entry.Value; + if (string.IsNullOrEmpty(key) || value == null) + { + throw new InvalidOperationException("Struct fields cannot have an empty key or a null value."); + } + + if (!first) + { + builder.Append(", "); + } + WriteString(builder, key); + builder.Append(": "); + WriteStructFieldValue(builder, value); + first = false; + } + builder.Append(first ? "}" : " }"); + } + + private void WriteStructFieldValue(StringBuilder builder, IMessage message) + { + var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message); + if (specifiedField == null) + { + throw new InvalidOperationException("Value message must contain a value for the oneof."); + } + + object value = specifiedField.Accessor.GetValue(message); + + switch (specifiedField.FieldNumber) + { + case Value.BoolValueFieldNumber: + case Value.StringValueFieldNumber: + case Value.NumberValueFieldNumber: + WriteSingleValue(builder, specifiedField, value); + return; + case Value.StructValueFieldNumber: + case Value.ListValueFieldNumber: + // Structs and ListValues are nested messages, and already well-known types. + var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message); + WriteWellKnownTypeValue(builder, nestedMessage.Descriptor, nestedMessage, true); + return; + case Value.NullValueFieldNumber: + WriteNull(builder); + return; + default: + throw new InvalidOperationException("Unexpected case in struct field: " + specifiedField.FieldNumber); + } + } + private void WriteList(StringBuilder builder, IFieldAccessor accessor, IList list) { builder.Append("[ "); |