aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/Google.Protobuf/JsonFormatter.cs
diff options
context:
space:
mode:
authorJon Skeet <jonskeet@google.com>2015-07-31 15:07:50 +0100
committerJon Skeet <jonskeet@google.com>2015-08-03 09:32:36 +0100
commite7caf15577e4fc8a024403bd8586041742d9e266 (patch)
treebad3eece629af358c2e808e26073c301524aa312 /csharp/src/Google.Protobuf/JsonFormatter.cs
parent115e6c735ec561d5260c134fa74ee0d5121a441b (diff)
downloadprotobuf-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/JsonFormatter.cs')
-rw-r--r--csharp/src/Google.Protobuf/JsonFormatter.cs84
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("[ ");