diff options
-rw-r--r-- | csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs | 39 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf.Test/project.json | 2 | ||||
-rwxr-xr-x | csharp/src/Google.Protobuf/JsonFormatter.cs | 56 |
3 files changed, 78 insertions, 19 deletions
diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs index 3b5bf773..53ac3dc9 100644 --- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs @@ -52,7 +52,7 @@ namespace Google.Protobuf [Test] public void DefaultValues_WhenOmitted() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(formatDefaultValues: false)); + var formatter = JsonFormatter.Default; AssertJson("{ }", formatter.Format(new ForeignMessage())); AssertJson("{ }", formatter.Format(new TestAllTypes())); @@ -62,7 +62,7 @@ namespace Google.Protobuf [Test] public void DefaultValues_WhenIncluded() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(formatDefaultValues: true)); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); AssertJson("{ 'c': 0 }", formatter.Format(new ForeignMessage())); } @@ -79,6 +79,23 @@ namespace Google.Protobuf } [Test] + public void EnumAsInt() + { + var message = new TestAllTypes + { + SingleForeignEnum = ForeignEnum.ForeignBar, + RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } + }; + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(true)); + var actualText = formatter.Format(message); + var expectedText = "{ " + + "'singleForeignEnum': 5, " + + "'repeatedForeignEnum': [ 6, 100, 4 ]" + + " }"; + AssertJson(expectedText, actualText); + } + + [Test] public void AllSingleFields() { var message = new TestAllTypes @@ -266,9 +283,9 @@ namespace Google.Protobuf } // We should get the same result both with and without "format default values". - var formatter = new JsonFormatter(new JsonFormatter.Settings(false)); + var formatter = JsonFormatter.Default; AssertJson(expectedJson, formatter.Format(message)); - formatter = new JsonFormatter(new JsonFormatter.Settings(true)); + formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); AssertJson(expectedJson, formatter.Format(message)); } @@ -300,7 +317,7 @@ namespace Google.Protobuf { // The actual JSON here is very large because there are lots of fields. Just test a couple of them. var message = new TestWellKnownTypes { Int32Field = 10 }; - var formatter = new JsonFormatter(new JsonFormatter.Settings(true)); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); var actualJson = formatter.Format(message); Assert.IsTrue(actualJson.Contains("\"int64Field\": null")); Assert.IsFalse(actualJson.Contains("\"int32Field\": null")); @@ -309,7 +326,7 @@ namespace Google.Protobuf [Test] public void OutputIsInNumericFieldOrder_NoDefaults() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(false)); + var formatter = JsonFormatter.Default; var message = new TestJsonFieldOrdering { PlainString = "p1", PlainInt32 = 2 }; AssertJson("{ 'plainString': 'p1', 'plainInt32': 2 }", formatter.Format(message)); message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; @@ -321,7 +338,7 @@ namespace Google.Protobuf [Test] public void OutputIsInNumericFieldOrder_WithDefaults() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(true)); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); var message = new TestJsonFieldOrdering(); AssertJson("{ 'plainString': '', 'plainInt32': 0 }", formatter.Format(message)); message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; @@ -485,7 +502,7 @@ namespace Google.Protobuf [Test] public void AnyWellKnownType() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(Timestamp.Descriptor))); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(Timestamp.Descriptor))); var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); var any = Any.Pack(timestamp); AssertJson("{ '@type': 'type.googleapis.com/google.protobuf.Timestamp', 'value': '1673-06-19T12:34:56Z' }", formatter.Format(any)); @@ -494,7 +511,7 @@ namespace Google.Protobuf [Test] public void AnyMessageType() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor))); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } }; var any = Any.Pack(message); AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any)); @@ -503,7 +520,7 @@ namespace Google.Protobuf [Test] public void AnyMessageType_CustomPrefix() { - var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor))); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); var message = new TestAllTypes { SingleInt32 = 10 }; var any = Any.Pack(message, "foo.bar/baz"); AssertJson("{ '@type': 'foo.bar/baz/protobuf_unittest.TestAllTypes', 'singleInt32': 10 }", formatter.Format(any)); @@ -513,7 +530,7 @@ namespace Google.Protobuf public void AnyNested() { var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor); - var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry)); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(registry)); // Nest an Any as the value of an Any. var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 }; diff --git a/csharp/src/Google.Protobuf.Test/project.json b/csharp/src/Google.Protobuf.Test/project.json index eaa7f79d..dff0ab73 100644 --- a/csharp/src/Google.Protobuf.Test/project.json +++ b/csharp/src/Google.Protobuf.Test/project.json @@ -42,4 +42,4 @@ } } } -}
\ No newline at end of file +} diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index 90c2e937..4ae10d8b 100755 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -375,14 +375,21 @@ namespace Google.Protobuf } else if (value is System.Enum) { - string name = OriginalEnumValueHelper.GetOriginalName(value); - if (name != null) + if (settings.FormatEnumsAsIntegers) { - WriteString(writer, name); + WriteValue(writer, (int)value); } else { - WriteValue(writer, (int)value); + string name = OriginalEnumValueHelper.GetOriginalName(value); + if (name != null) + { + WriteString(writer, name); + } + else + { + WriteValue(writer, (int)value); + } } } else if (value is float || value is double) @@ -778,7 +785,11 @@ namespace Google.Protobuf /// </summary> public TypeRegistry TypeRegistry { get; } - // TODO: Work out how we're going to scale this to multiple settings. "WithXyz" methods? + /// <summary> + /// Whether to format enums as ints. Defaults to false. + /// </summary> + public bool FormatEnumsAsIntegers { get; } + /// <summary> /// Creates a new <see cref="Settings"/> object with the specified formatting of default values @@ -795,11 +806,42 @@ namespace Google.Protobuf /// </summary> /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param> /// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param> - public Settings(bool formatDefaultValues, TypeRegistry typeRegistry) + public Settings(bool formatDefaultValues, TypeRegistry typeRegistry) : this(formatDefaultValues, typeRegistry, false) + { + } + + /// <summary> + /// Creates a new <see cref="Settings"/> object with the specified parameters. + /// </summary> + /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param> + /// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages. TypeRegistry.Empty will be used if it is null.</param> + /// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param> + private Settings(bool formatDefaultValues, + TypeRegistry typeRegistry, + bool formatEnumsAsIntegers) { FormatDefaultValues = formatDefaultValues; - TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry)); + TypeRegistry = typeRegistry ?? TypeRegistry.Empty; + FormatEnumsAsIntegers = formatEnumsAsIntegers; } + + /// <summary> + /// Creates a new <see cref="Settings"/> object with the specified formatting of default values and the current settings. + /// </summary> + /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param> + public Settings WithFormatDefaultValues(bool formatDefaultValues) => new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers); + + /// <summary> + /// Creates a new <see cref="Settings"/> object with the specified type registry and the current settings. + /// </summary> + /// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param> + public Settings WithTypeRegistry(TypeRegistry typeRegistry) => new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers); + + /// <summary> + /// Creates a new <see cref="Settings"/> object with the specified enums formatting option and the current settings. + /// </summary> + /// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param> + public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers); } // Effectively a cache of mapping from enum values to the original name as specified in the proto file, |