1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf.util; 32 33 import com.google.common.collect.ImmutableSet; 34 import com.google.protobuf.Any; 35 import com.google.protobuf.BoolValue; 36 import com.google.protobuf.ByteString; 37 import com.google.protobuf.BytesValue; 38 import com.google.protobuf.Descriptors.Descriptor; 39 import com.google.protobuf.Descriptors.FieldDescriptor; 40 import com.google.protobuf.DoubleValue; 41 import com.google.protobuf.FloatValue; 42 import com.google.protobuf.Int32Value; 43 import com.google.protobuf.Int64Value; 44 import com.google.protobuf.InvalidProtocolBufferException; 45 import com.google.protobuf.ListValue; 46 import com.google.protobuf.Message; 47 import com.google.protobuf.NullValue; 48 import com.google.protobuf.StringValue; 49 import com.google.protobuf.Struct; 50 import com.google.protobuf.UInt32Value; 51 import com.google.protobuf.UInt64Value; 52 import com.google.protobuf.Value; 53 import com.google.protobuf.util.JsonFormat.TypeRegistry; 54 import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes; 55 import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes.AliasedEnum; 56 import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes.NestedEnum; 57 import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes.NestedMessage; 58 import com.google.protobuf.util.proto.JsonTestProto.TestAny; 59 import com.google.protobuf.util.proto.JsonTestProto.TestCustomJsonName; 60 import com.google.protobuf.util.proto.JsonTestProto.TestDuration; 61 import com.google.protobuf.util.proto.JsonTestProto.TestFieldMask; 62 import com.google.protobuf.util.proto.JsonTestProto.TestMap; 63 import com.google.protobuf.util.proto.JsonTestProto.TestOneof; 64 import com.google.protobuf.util.proto.JsonTestProto.TestRecursive; 65 import com.google.protobuf.util.proto.JsonTestProto.TestStruct; 66 import com.google.protobuf.util.proto.JsonTestProto.TestTimestamp; 67 import com.google.protobuf.util.proto.JsonTestProto.TestWrappers; 68 import java.io.IOException; 69 import java.io.InputStream; 70 import java.io.InputStreamReader; 71 import java.io.Reader; 72 import java.io.StringReader; 73 import java.math.BigDecimal; 74 import java.math.BigInteger; 75 import java.util.Collections; 76 import java.util.HashSet; 77 import java.util.Locale; 78 import java.util.Set; 79 import junit.framework.TestCase; 80 81 public class JsonFormatTest extends TestCase { JsonFormatTest()82 public JsonFormatTest() { 83 // Test that locale does not affect JsonFormat. 84 Locale.setDefault(Locale.forLanguageTag("hi-IN")); 85 } 86 setAllFields(TestAllTypes.Builder builder)87 private void setAllFields(TestAllTypes.Builder builder) { 88 builder.setOptionalInt32(1234); 89 builder.setOptionalInt64(1234567890123456789L); 90 builder.setOptionalUint32(5678); 91 builder.setOptionalUint64(2345678901234567890L); 92 builder.setOptionalSint32(9012); 93 builder.setOptionalSint64(3456789012345678901L); 94 builder.setOptionalFixed32(3456); 95 builder.setOptionalFixed64(4567890123456789012L); 96 builder.setOptionalSfixed32(7890); 97 builder.setOptionalSfixed64(5678901234567890123L); 98 builder.setOptionalFloat(1.5f); 99 builder.setOptionalDouble(1.25); 100 builder.setOptionalBool(true); 101 builder.setOptionalString("Hello world!"); 102 builder.setOptionalBytes(ByteString.copyFrom(new byte[] {0, 1, 2})); 103 builder.setOptionalNestedEnum(NestedEnum.BAR); 104 builder.getOptionalNestedMessageBuilder().setValue(100); 105 106 builder.addRepeatedInt32(1234); 107 builder.addRepeatedInt64(1234567890123456789L); 108 builder.addRepeatedUint32(5678); 109 builder.addRepeatedUint64(2345678901234567890L); 110 builder.addRepeatedSint32(9012); 111 builder.addRepeatedSint64(3456789012345678901L); 112 builder.addRepeatedFixed32(3456); 113 builder.addRepeatedFixed64(4567890123456789012L); 114 builder.addRepeatedSfixed32(7890); 115 builder.addRepeatedSfixed64(5678901234567890123L); 116 builder.addRepeatedFloat(1.5f); 117 builder.addRepeatedDouble(1.25); 118 builder.addRepeatedBool(true); 119 builder.addRepeatedString("Hello world!"); 120 builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {0, 1, 2})); 121 builder.addRepeatedNestedEnum(NestedEnum.BAR); 122 builder.addRepeatedNestedMessageBuilder().setValue(100); 123 124 builder.addRepeatedInt32(234); 125 builder.addRepeatedInt64(234567890123456789L); 126 builder.addRepeatedUint32(678); 127 builder.addRepeatedUint64(345678901234567890L); 128 builder.addRepeatedSint32(012); 129 builder.addRepeatedSint64(456789012345678901L); 130 builder.addRepeatedFixed32(456); 131 builder.addRepeatedFixed64(567890123456789012L); 132 builder.addRepeatedSfixed32(890); 133 builder.addRepeatedSfixed64(678901234567890123L); 134 builder.addRepeatedFloat(11.5f); 135 builder.addRepeatedDouble(11.25); 136 builder.addRepeatedBool(true); 137 builder.addRepeatedString("ello world!"); 138 builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {1, 2})); 139 builder.addRepeatedNestedEnum(NestedEnum.BAZ); 140 builder.addRepeatedNestedMessageBuilder().setValue(200); 141 } 142 assertRoundTripEquals(Message message)143 private void assertRoundTripEquals(Message message) throws Exception { 144 assertRoundTripEquals(message, TypeRegistry.getEmptyTypeRegistry()); 145 } 146 assertRoundTripEquals(Message message, TypeRegistry registry)147 private void assertRoundTripEquals(Message message, TypeRegistry registry) throws Exception { 148 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 149 JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry); 150 Message.Builder builder = message.newBuilderForType(); 151 parser.merge(printer.print(message), builder); 152 Message parsedMessage = builder.build(); 153 assertEquals(message.toString(), parsedMessage.toString()); 154 } 155 assertRoundTripEquals(Message message, com.google.protobuf.TypeRegistry registry)156 private void assertRoundTripEquals(Message message, com.google.protobuf.TypeRegistry registry) 157 throws Exception { 158 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 159 JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry); 160 Message.Builder builder = message.newBuilderForType(); 161 parser.merge(printer.print(message), builder); 162 Message parsedMessage = builder.build(); 163 assertEquals(message.toString(), parsedMessage.toString()); 164 } 165 toJsonString(Message message)166 private String toJsonString(Message message) throws IOException { 167 return JsonFormat.printer().print(message); 168 } toCompactJsonString(Message message)169 private String toCompactJsonString(Message message) throws IOException { 170 return JsonFormat.printer().omittingInsignificantWhitespace().print(message); 171 } toSortedJsonString(Message message)172 private String toSortedJsonString(Message message) throws IOException { 173 return JsonFormat.printer().sortingMapKeys().print(message); 174 } 175 mergeFromJson(String json, Message.Builder builder)176 private void mergeFromJson(String json, Message.Builder builder) throws IOException { 177 JsonFormat.parser().merge(json, builder); 178 } 179 mergeFromJsonIgnoringUnknownFields(String json, Message.Builder builder)180 private void mergeFromJsonIgnoringUnknownFields(String json, Message.Builder builder) 181 throws IOException { 182 JsonFormat.parser().ignoringUnknownFields().merge(json, builder); 183 } 184 testAllFields()185 public void testAllFields() throws Exception { 186 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 187 setAllFields(builder); 188 TestAllTypes message = builder.build(); 189 190 assertEquals( 191 "{\n" 192 + " \"optionalInt32\": 1234,\n" 193 + " \"optionalInt64\": \"1234567890123456789\",\n" 194 + " \"optionalUint32\": 5678,\n" 195 + " \"optionalUint64\": \"2345678901234567890\",\n" 196 + " \"optionalSint32\": 9012,\n" 197 + " \"optionalSint64\": \"3456789012345678901\",\n" 198 + " \"optionalFixed32\": 3456,\n" 199 + " \"optionalFixed64\": \"4567890123456789012\",\n" 200 + " \"optionalSfixed32\": 7890,\n" 201 + " \"optionalSfixed64\": \"5678901234567890123\",\n" 202 + " \"optionalFloat\": 1.5,\n" 203 + " \"optionalDouble\": 1.25,\n" 204 + " \"optionalBool\": true,\n" 205 + " \"optionalString\": \"Hello world!\",\n" 206 + " \"optionalBytes\": \"AAEC\",\n" 207 + " \"optionalNestedMessage\": {\n" 208 + " \"value\": 100\n" 209 + " },\n" 210 + " \"optionalNestedEnum\": \"BAR\",\n" 211 + " \"repeatedInt32\": [1234, 234],\n" 212 + " \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n" 213 + " \"repeatedUint32\": [5678, 678],\n" 214 + " \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n" 215 + " \"repeatedSint32\": [9012, 10],\n" 216 + " \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n" 217 + " \"repeatedFixed32\": [3456, 456],\n" 218 + " \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n" 219 + " \"repeatedSfixed32\": [7890, 890],\n" 220 + " \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n" 221 + " \"repeatedFloat\": [1.5, 11.5],\n" 222 + " \"repeatedDouble\": [1.25, 11.25],\n" 223 + " \"repeatedBool\": [true, true],\n" 224 + " \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n" 225 + " \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n" 226 + " \"repeatedNestedMessage\": [{\n" 227 + " \"value\": 100\n" 228 + " }, {\n" 229 + " \"value\": 200\n" 230 + " }],\n" 231 + " \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n" 232 + "}", 233 toJsonString(message)); 234 235 assertRoundTripEquals(message); 236 } 237 testUnknownEnumValues()238 public void testUnknownEnumValues() throws Exception { 239 TestAllTypes message = 240 TestAllTypes.newBuilder() 241 .setOptionalNestedEnumValue(12345) 242 .addRepeatedNestedEnumValue(12345) 243 .addRepeatedNestedEnumValue(0) 244 .build(); 245 assertEquals( 246 "{\n" 247 + " \"optionalNestedEnum\": 12345,\n" 248 + " \"repeatedNestedEnum\": [12345, \"FOO\"]\n" 249 + "}", 250 toJsonString(message)); 251 assertRoundTripEquals(message); 252 253 TestMap.Builder mapBuilder = TestMap.newBuilder(); 254 mapBuilder.putInt32ToEnumMapValue(1, 0); 255 mapBuilder.putInt32ToEnumMapValue(2, 12345); 256 TestMap mapMessage = mapBuilder.build(); 257 assertEquals( 258 "{\n" 259 + " \"int32ToEnumMap\": {\n" 260 + " \"1\": \"FOO\",\n" 261 + " \"2\": 12345\n" 262 + " }\n" 263 + "}", 264 toJsonString(mapMessage)); 265 assertRoundTripEquals(mapMessage); 266 } 267 testSpecialFloatValues()268 public void testSpecialFloatValues() throws Exception { 269 TestAllTypes message = 270 TestAllTypes.newBuilder() 271 .addRepeatedFloat(Float.NaN) 272 .addRepeatedFloat(Float.POSITIVE_INFINITY) 273 .addRepeatedFloat(Float.NEGATIVE_INFINITY) 274 .addRepeatedDouble(Double.NaN) 275 .addRepeatedDouble(Double.POSITIVE_INFINITY) 276 .addRepeatedDouble(Double.NEGATIVE_INFINITY) 277 .build(); 278 assertEquals( 279 "{\n" 280 + " \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n" 281 + " \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n" 282 + "}", 283 toJsonString(message)); 284 285 assertRoundTripEquals(message); 286 } 287 testParserAcceptStringForNumericField()288 public void testParserAcceptStringForNumericField() throws Exception { 289 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 290 mergeFromJson( 291 "{\n" 292 + " \"optionalInt32\": \"1234\",\n" 293 + " \"optionalUint32\": \"5678\",\n" 294 + " \"optionalSint32\": \"9012\",\n" 295 + " \"optionalFixed32\": \"3456\",\n" 296 + " \"optionalSfixed32\": \"7890\",\n" 297 + " \"optionalFloat\": \"1.5\",\n" 298 + " \"optionalDouble\": \"1.25\",\n" 299 + " \"optionalBool\": \"true\"\n" 300 + "}", 301 builder); 302 TestAllTypes message = builder.build(); 303 assertEquals(1234, message.getOptionalInt32()); 304 assertEquals(5678, message.getOptionalUint32()); 305 assertEquals(9012, message.getOptionalSint32()); 306 assertEquals(3456, message.getOptionalFixed32()); 307 assertEquals(7890, message.getOptionalSfixed32()); 308 assertEquals(1.5f, message.getOptionalFloat(), 0.0f); 309 assertEquals(1.25, message.getOptionalDouble(), 0.0); 310 assertEquals(true, message.getOptionalBool()); 311 } 312 testParserAcceptFloatingPointValueForIntegerField()313 public void testParserAcceptFloatingPointValueForIntegerField() throws Exception { 314 // Test that numeric values like "1.000", "1e5" will also be accepted. 315 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 316 mergeFromJson( 317 "{\n" 318 + " \"repeatedInt32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n" 319 + " \"repeatedUint32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n" 320 + " \"repeatedInt64\": [1.000, 1e5, \"1.000\", \"1e5\"],\n" 321 + " \"repeatedUint64\": [1.000, 1e5, \"1.000\", \"1e5\"]\n" 322 + "}", 323 builder); 324 int[] expectedValues = new int[] {1, 100000, 1, 100000}; 325 assertEquals(4, builder.getRepeatedInt32Count()); 326 assertEquals(4, builder.getRepeatedUint32Count()); 327 assertEquals(4, builder.getRepeatedInt64Count()); 328 assertEquals(4, builder.getRepeatedUint64Count()); 329 for (int i = 0; i < 4; ++i) { 330 assertEquals(expectedValues[i], builder.getRepeatedInt32(i)); 331 assertEquals(expectedValues[i], builder.getRepeatedUint32(i)); 332 assertEquals(expectedValues[i], builder.getRepeatedInt64(i)); 333 assertEquals(expectedValues[i], builder.getRepeatedUint64(i)); 334 } 335 336 // Non-integers will still be rejected. 337 assertRejects("optionalInt32", "1.5"); 338 assertRejects("optionalUint32", "1.5"); 339 assertRejects("optionalInt64", "1.5"); 340 assertRejects("optionalUint64", "1.5"); 341 } 342 assertRejects(String name, String value)343 private void assertRejects(String name, String value) { 344 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 345 try { 346 // Numeric form is rejected. 347 mergeFromJson("{\"" + name + "\":" + value + "}", builder); 348 fail("Exception is expected."); 349 } catch (IOException e) { 350 // Expected. 351 } 352 try { 353 // String form is also rejected. 354 mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder); 355 fail("Exception is expected."); 356 } catch (IOException e) { 357 // Expected. 358 } 359 } 360 assertAccepts(String name, String value)361 private void assertAccepts(String name, String value) throws IOException { 362 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 363 // Both numeric form and string form are accepted. 364 mergeFromJson("{\"" + name + "\":" + value + "}", builder); 365 builder.clear(); 366 mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder); 367 } 368 testParserRejectOutOfRangeNumericValues()369 public void testParserRejectOutOfRangeNumericValues() throws Exception { 370 assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE)); 371 assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE)); 372 assertRejects("optionalInt32", String.valueOf(Integer.MAX_VALUE + 1L)); 373 assertRejects("optionalInt32", String.valueOf(Integer.MIN_VALUE - 1L)); 374 375 assertAccepts("optionalUint32", String.valueOf(Integer.MAX_VALUE + 1L)); 376 assertRejects("optionalUint32", "123456789012345"); 377 assertRejects("optionalUint32", "-1"); 378 379 BigInteger one = new BigInteger("1"); 380 BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE)); 381 BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE)); 382 assertAccepts("optionalInt64", maxLong.toString()); 383 assertAccepts("optionalInt64", minLong.toString()); 384 assertRejects("optionalInt64", maxLong.add(one).toString()); 385 assertRejects("optionalInt64", minLong.subtract(one).toString()); 386 387 assertAccepts("optionalUint64", maxLong.add(one).toString()); 388 assertRejects("optionalUint64", "1234567890123456789012345"); 389 assertRejects("optionalUint64", "-1"); 390 391 assertAccepts("optionalBool", "true"); 392 assertRejects("optionalBool", "1"); 393 assertRejects("optionalBool", "0"); 394 395 assertAccepts("optionalFloat", String.valueOf(Float.MAX_VALUE)); 396 assertAccepts("optionalFloat", String.valueOf(-Float.MAX_VALUE)); 397 assertRejects("optionalFloat", String.valueOf(Double.MAX_VALUE)); 398 assertRejects("optionalFloat", String.valueOf(-Double.MAX_VALUE)); 399 400 BigDecimal moreThanOne = new BigDecimal("1.000001"); 401 BigDecimal maxDouble = new BigDecimal(Double.MAX_VALUE); 402 BigDecimal minDouble = new BigDecimal(-Double.MAX_VALUE); 403 assertAccepts("optionalDouble", maxDouble.toString()); 404 assertAccepts("optionalDouble", minDouble.toString()); 405 assertRejects("optionalDouble", maxDouble.multiply(moreThanOne).toString()); 406 assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString()); 407 } 408 testParserAcceptNull()409 public void testParserAcceptNull() throws Exception { 410 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 411 mergeFromJson( 412 "{\n" 413 + " \"optionalInt32\": null,\n" 414 + " \"optionalInt64\": null,\n" 415 + " \"optionalUint32\": null,\n" 416 + " \"optionalUint64\": null,\n" 417 + " \"optionalSint32\": null,\n" 418 + " \"optionalSint64\": null,\n" 419 + " \"optionalFixed32\": null,\n" 420 + " \"optionalFixed64\": null,\n" 421 + " \"optionalSfixed32\": null,\n" 422 + " \"optionalSfixed64\": null,\n" 423 + " \"optionalFloat\": null,\n" 424 + " \"optionalDouble\": null,\n" 425 + " \"optionalBool\": null,\n" 426 + " \"optionalString\": null,\n" 427 + " \"optionalBytes\": null,\n" 428 + " \"optionalNestedMessage\": null,\n" 429 + " \"optionalNestedEnum\": null,\n" 430 + " \"repeatedInt32\": null,\n" 431 + " \"repeatedInt64\": null,\n" 432 + " \"repeatedUint32\": null,\n" 433 + " \"repeatedUint64\": null,\n" 434 + " \"repeatedSint32\": null,\n" 435 + " \"repeatedSint64\": null,\n" 436 + " \"repeatedFixed32\": null,\n" 437 + " \"repeatedFixed64\": null,\n" 438 + " \"repeatedSfixed32\": null,\n" 439 + " \"repeatedSfixed64\": null,\n" 440 + " \"repeatedFloat\": null,\n" 441 + " \"repeatedDouble\": null,\n" 442 + " \"repeatedBool\": null,\n" 443 + " \"repeatedString\": null,\n" 444 + " \"repeatedBytes\": null,\n" 445 + " \"repeatedNestedMessage\": null,\n" 446 + " \"repeatedNestedEnum\": null\n" 447 + "}", 448 builder); 449 TestAllTypes message = builder.build(); 450 assertEquals(TestAllTypes.getDefaultInstance(), message); 451 452 // Repeated field elements cannot be null. 453 try { 454 builder = TestAllTypes.newBuilder(); 455 mergeFromJson("{\n" + " \"repeatedInt32\": [null, null],\n" + "}", builder); 456 fail(); 457 } catch (InvalidProtocolBufferException e) { 458 // Exception expected. 459 } 460 461 try { 462 builder = TestAllTypes.newBuilder(); 463 mergeFromJson("{\n" + " \"repeatedNestedMessage\": [null, null],\n" + "}", builder); 464 fail(); 465 } catch (InvalidProtocolBufferException e) { 466 // Exception expected. 467 } 468 } 469 testNullInOneof()470 public void testNullInOneof() throws Exception { 471 TestOneof.Builder builder = TestOneof.newBuilder(); 472 mergeFromJson("{\n" + " \"oneofNullValue\": null \n" + "}", builder); 473 TestOneof message = builder.build(); 474 assertEquals(TestOneof.OneofFieldCase.ONEOF_NULL_VALUE, message.getOneofFieldCase()); 475 assertEquals(NullValue.NULL_VALUE, message.getOneofNullValue()); 476 } 477 testNullFirstInDuplicateOneof()478 public void testNullFirstInDuplicateOneof() throws Exception { 479 TestOneof.Builder builder = TestOneof.newBuilder(); 480 mergeFromJson("{\"oneofNestedMessage\": null, \"oneofInt32\": 1}", builder); 481 TestOneof message = builder.build(); 482 assertEquals(1, message.getOneofInt32()); 483 } 484 testNullLastInDuplicateOneof()485 public void testNullLastInDuplicateOneof() throws Exception { 486 TestOneof.Builder builder = TestOneof.newBuilder(); 487 mergeFromJson("{\"oneofInt32\": 1, \"oneofNestedMessage\": null}", builder); 488 TestOneof message = builder.build(); 489 assertEquals(1, message.getOneofInt32()); 490 } 491 testParserRejectDuplicatedFields()492 public void testParserRejectDuplicatedFields() throws Exception { 493 // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last 494 // one if multiple entries have the same name. This is not the desired behavior but it can 495 // only be fixed by using our own parser. Here we only test the cases where the names are 496 // different but still referring to the same field. 497 498 // Duplicated optional fields. 499 try { 500 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 501 mergeFromJson( 502 "{\n" 503 + " \"optionalNestedMessage\": {},\n" 504 + " \"optional_nested_message\": {}\n" 505 + "}", 506 builder); 507 fail(); 508 } catch (InvalidProtocolBufferException e) { 509 // Exception expected. 510 } 511 512 // Duplicated repeated fields. 513 try { 514 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 515 mergeFromJson( 516 "{\n" 517 + " \"repeatedInt32\": [1, 2],\n" 518 + " \"repeated_int32\": [5, 6]\n" 519 + "}", 520 builder); 521 fail(); 522 } catch (InvalidProtocolBufferException e) { 523 // Exception expected. 524 } 525 526 // Duplicated oneof fields, same name. 527 try { 528 TestOneof.Builder builder = TestOneof.newBuilder(); 529 mergeFromJson("{\n" + " \"oneofInt32\": 1,\n" + " \"oneof_int32\": 2\n" + "}", builder); 530 fail(); 531 } catch (InvalidProtocolBufferException e) { 532 // Exception expected. 533 } 534 535 // Duplicated oneof fields, different name. 536 try { 537 TestOneof.Builder builder = TestOneof.newBuilder(); 538 mergeFromJson( 539 "{\n" + " \"oneofInt32\": 1,\n" + " \"oneofNullValue\": null\n" + "}", builder); 540 fail(); 541 } catch (InvalidProtocolBufferException e) { 542 // Exception expected. 543 } 544 } 545 testMapFields()546 public void testMapFields() throws Exception { 547 TestMap.Builder builder = TestMap.newBuilder(); 548 builder.putInt32ToInt32Map(1, 10); 549 builder.putInt64ToInt32Map(1234567890123456789L, 10); 550 builder.putUint32ToInt32Map(2, 20); 551 builder.putUint64ToInt32Map(2234567890123456789L, 20); 552 builder.putSint32ToInt32Map(3, 30); 553 builder.putSint64ToInt32Map(3234567890123456789L, 30); 554 builder.putFixed32ToInt32Map(4, 40); 555 builder.putFixed64ToInt32Map(4234567890123456789L, 40); 556 builder.putSfixed32ToInt32Map(5, 50); 557 builder.putSfixed64ToInt32Map(5234567890123456789L, 50); 558 builder.putBoolToInt32Map(false, 6); 559 builder.putStringToInt32Map("Hello", 10); 560 561 builder.putInt32ToInt64Map(1, 1234567890123456789L); 562 builder.putInt32ToUint32Map(2, 20); 563 builder.putInt32ToUint64Map(2, 2234567890123456789L); 564 builder.putInt32ToSint32Map(3, 30); 565 builder.putInt32ToSint64Map(3, 3234567890123456789L); 566 builder.putInt32ToFixed32Map(4, 40); 567 builder.putInt32ToFixed64Map(4, 4234567890123456789L); 568 builder.putInt32ToSfixed32Map(5, 50); 569 builder.putInt32ToSfixed64Map(5, 5234567890123456789L); 570 builder.putInt32ToFloatMap(6, 1.5f); 571 builder.putInt32ToDoubleMap(6, 1.25); 572 builder.putInt32ToBoolMap(7, false); 573 builder.putInt32ToStringMap(7, "World"); 574 builder.putInt32ToBytesMap(8, ByteString.copyFrom(new byte[] {1, 2, 3})); 575 builder.putInt32ToMessageMap(8, NestedMessage.newBuilder().setValue(1234).build()); 576 builder.putInt32ToEnumMap(9, NestedEnum.BAR); 577 TestMap message = builder.build(); 578 579 assertEquals( 580 "{\n" 581 + " \"int32ToInt32Map\": {\n" 582 + " \"1\": 10\n" 583 + " },\n" 584 + " \"int64ToInt32Map\": {\n" 585 + " \"1234567890123456789\": 10\n" 586 + " },\n" 587 + " \"uint32ToInt32Map\": {\n" 588 + " \"2\": 20\n" 589 + " },\n" 590 + " \"uint64ToInt32Map\": {\n" 591 + " \"2234567890123456789\": 20\n" 592 + " },\n" 593 + " \"sint32ToInt32Map\": {\n" 594 + " \"3\": 30\n" 595 + " },\n" 596 + " \"sint64ToInt32Map\": {\n" 597 + " \"3234567890123456789\": 30\n" 598 + " },\n" 599 + " \"fixed32ToInt32Map\": {\n" 600 + " \"4\": 40\n" 601 + " },\n" 602 + " \"fixed64ToInt32Map\": {\n" 603 + " \"4234567890123456789\": 40\n" 604 + " },\n" 605 + " \"sfixed32ToInt32Map\": {\n" 606 + " \"5\": 50\n" 607 + " },\n" 608 + " \"sfixed64ToInt32Map\": {\n" 609 + " \"5234567890123456789\": 50\n" 610 + " },\n" 611 + " \"boolToInt32Map\": {\n" 612 + " \"false\": 6\n" 613 + " },\n" 614 + " \"stringToInt32Map\": {\n" 615 + " \"Hello\": 10\n" 616 + " },\n" 617 + " \"int32ToInt64Map\": {\n" 618 + " \"1\": \"1234567890123456789\"\n" 619 + " },\n" 620 + " \"int32ToUint32Map\": {\n" 621 + " \"2\": 20\n" 622 + " },\n" 623 + " \"int32ToUint64Map\": {\n" 624 + " \"2\": \"2234567890123456789\"\n" 625 + " },\n" 626 + " \"int32ToSint32Map\": {\n" 627 + " \"3\": 30\n" 628 + " },\n" 629 + " \"int32ToSint64Map\": {\n" 630 + " \"3\": \"3234567890123456789\"\n" 631 + " },\n" 632 + " \"int32ToFixed32Map\": {\n" 633 + " \"4\": 40\n" 634 + " },\n" 635 + " \"int32ToFixed64Map\": {\n" 636 + " \"4\": \"4234567890123456789\"\n" 637 + " },\n" 638 + " \"int32ToSfixed32Map\": {\n" 639 + " \"5\": 50\n" 640 + " },\n" 641 + " \"int32ToSfixed64Map\": {\n" 642 + " \"5\": \"5234567890123456789\"\n" 643 + " },\n" 644 + " \"int32ToFloatMap\": {\n" 645 + " \"6\": 1.5\n" 646 + " },\n" 647 + " \"int32ToDoubleMap\": {\n" 648 + " \"6\": 1.25\n" 649 + " },\n" 650 + " \"int32ToBoolMap\": {\n" 651 + " \"7\": false\n" 652 + " },\n" 653 + " \"int32ToStringMap\": {\n" 654 + " \"7\": \"World\"\n" 655 + " },\n" 656 + " \"int32ToBytesMap\": {\n" 657 + " \"8\": \"AQID\"\n" 658 + " },\n" 659 + " \"int32ToMessageMap\": {\n" 660 + " \"8\": {\n" 661 + " \"value\": 1234\n" 662 + " }\n" 663 + " },\n" 664 + " \"int32ToEnumMap\": {\n" 665 + " \"9\": \"BAR\"\n" 666 + " }\n" 667 + "}", 668 toJsonString(message)); 669 assertRoundTripEquals(message); 670 671 // Test multiple entries. 672 builder = TestMap.newBuilder(); 673 builder.putInt32ToInt32Map(1, 2); 674 builder.putInt32ToInt32Map(3, 4); 675 message = builder.build(); 676 677 assertEquals( 678 "{\n" + " \"int32ToInt32Map\": {\n" + " \"1\": 2,\n" + " \"3\": 4\n" + " }\n" + "}", 679 toJsonString(message)); 680 assertRoundTripEquals(message); 681 } 682 testMapNullValueIsRejected()683 public void testMapNullValueIsRejected() throws Exception { 684 try { 685 TestMap.Builder builder = TestMap.newBuilder(); 686 mergeFromJson( 687 "{\n" 688 + " \"int32ToInt32Map\": {null: 1},\n" 689 + " \"int32ToMessageMap\": {null: 2}\n" 690 + "}", 691 builder); 692 fail(); 693 } catch (InvalidProtocolBufferException e) { 694 // Exception expected. 695 } 696 697 try { 698 TestMap.Builder builder = TestMap.newBuilder(); 699 mergeFromJson( 700 "{\n" 701 + " \"int32ToInt32Map\": {\"1\": null},\n" 702 + " \"int32ToMessageMap\": {\"2\": null}\n" 703 + "}", 704 builder); 705 fail(); 706 707 } catch (InvalidProtocolBufferException e) { 708 // Exception expected. 709 } 710 } 711 testMapEnumNullValueIsIgnored()712 public void testMapEnumNullValueIsIgnored() throws Exception { 713 TestMap.Builder builder = TestMap.newBuilder(); 714 mergeFromJsonIgnoringUnknownFields( 715 "{\n" + " \"int32ToEnumMap\": {\"1\": null}\n" + "}", builder); 716 TestMap map = builder.build(); 717 assertEquals(0, map.getInt32ToEnumMapMap().size()); 718 } 719 testParserAcceptNonQuotedObjectKey()720 public void testParserAcceptNonQuotedObjectKey() throws Exception { 721 TestMap.Builder builder = TestMap.newBuilder(); 722 mergeFromJson( 723 "{\n" + " int32ToInt32Map: {1: 2},\n" + " stringToInt32Map: {hello: 3}\n" + "}", builder); 724 TestMap message = builder.build(); 725 assertEquals(2, message.getInt32ToInt32Map().get(1).intValue()); 726 assertEquals(3, message.getStringToInt32Map().get("hello").intValue()); 727 } 728 testWrappers()729 public void testWrappers() throws Exception { 730 TestWrappers.Builder builder = TestWrappers.newBuilder(); 731 builder.getBoolValueBuilder().setValue(false); 732 builder.getInt32ValueBuilder().setValue(0); 733 builder.getInt64ValueBuilder().setValue(0); 734 builder.getUint32ValueBuilder().setValue(0); 735 builder.getUint64ValueBuilder().setValue(0); 736 builder.getFloatValueBuilder().setValue(0.0f); 737 builder.getDoubleValueBuilder().setValue(0.0); 738 builder.getStringValueBuilder().setValue(""); 739 builder.getBytesValueBuilder().setValue(ByteString.EMPTY); 740 TestWrappers message = builder.build(); 741 742 assertEquals( 743 "{\n" 744 + " \"int32Value\": 0,\n" 745 + " \"uint32Value\": 0,\n" 746 + " \"int64Value\": \"0\",\n" 747 + " \"uint64Value\": \"0\",\n" 748 + " \"floatValue\": 0.0,\n" 749 + " \"doubleValue\": 0.0,\n" 750 + " \"boolValue\": false,\n" 751 + " \"stringValue\": \"\",\n" 752 + " \"bytesValue\": \"\"\n" 753 + "}", 754 toJsonString(message)); 755 assertRoundTripEquals(message); 756 757 builder = TestWrappers.newBuilder(); 758 builder.getBoolValueBuilder().setValue(true); 759 builder.getInt32ValueBuilder().setValue(1); 760 builder.getInt64ValueBuilder().setValue(2); 761 builder.getUint32ValueBuilder().setValue(3); 762 builder.getUint64ValueBuilder().setValue(4); 763 builder.getFloatValueBuilder().setValue(5.0f); 764 builder.getDoubleValueBuilder().setValue(6.0); 765 builder.getStringValueBuilder().setValue("7"); 766 builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[] {8})); 767 message = builder.build(); 768 769 assertEquals( 770 "{\n" 771 + " \"int32Value\": 1,\n" 772 + " \"uint32Value\": 3,\n" 773 + " \"int64Value\": \"2\",\n" 774 + " \"uint64Value\": \"4\",\n" 775 + " \"floatValue\": 5.0,\n" 776 + " \"doubleValue\": 6.0,\n" 777 + " \"boolValue\": true,\n" 778 + " \"stringValue\": \"7\",\n" 779 + " \"bytesValue\": \"CA==\"\n" 780 + "}", 781 toJsonString(message)); 782 assertRoundTripEquals(message); 783 } 784 testTimestamp()785 public void testTimestamp() throws Exception { 786 TestTimestamp message = 787 TestTimestamp.newBuilder() 788 .setTimestampValue(Timestamps.parse("1970-01-01T00:00:00Z")) 789 .build(); 790 791 assertEquals( 792 "{\n" + " \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" + "}", toJsonString(message)); 793 assertRoundTripEquals(message); 794 } 795 testDuration()796 public void testDuration() throws Exception { 797 TestDuration message = 798 TestDuration.newBuilder().setDurationValue(Durations.parse("12345s")).build(); 799 800 assertEquals("{\n" + " \"durationValue\": \"12345s\"\n" + "}", toJsonString(message)); 801 assertRoundTripEquals(message); 802 } 803 testFieldMask()804 public void testFieldMask() throws Exception { 805 TestFieldMask message = 806 TestFieldMask.newBuilder() 807 .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz,foo_bar.baz")) 808 .build(); 809 810 assertEquals( 811 "{\n" + " \"fieldMaskValue\": \"foo.bar,baz,fooBar.baz\"\n" + "}", toJsonString(message)); 812 assertRoundTripEquals(message); 813 } 814 testStruct()815 public void testStruct() throws Exception { 816 // Build a struct with all possible values. 817 TestStruct.Builder builder = TestStruct.newBuilder(); 818 Struct.Builder structBuilder = builder.getStructValueBuilder(); 819 structBuilder.putFields("null_value", Value.newBuilder().setNullValueValue(0).build()); 820 structBuilder.putFields("number_value", Value.newBuilder().setNumberValue(1.25).build()); 821 structBuilder.putFields("string_value", Value.newBuilder().setStringValue("hello").build()); 822 Struct.Builder subStructBuilder = Struct.newBuilder(); 823 subStructBuilder.putFields("number_value", Value.newBuilder().setNumberValue(1234).build()); 824 structBuilder.putFields( 825 "struct_value", Value.newBuilder().setStructValue(subStructBuilder.build()).build()); 826 ListValue.Builder listBuilder = ListValue.newBuilder(); 827 listBuilder.addValues(Value.newBuilder().setNumberValue(1.125).build()); 828 listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build()); 829 structBuilder.putFields( 830 "list_value", Value.newBuilder().setListValue(listBuilder.build()).build()); 831 TestStruct message = builder.build(); 832 833 assertEquals( 834 "{\n" 835 + " \"structValue\": {\n" 836 + " \"null_value\": null,\n" 837 + " \"number_value\": 1.25,\n" 838 + " \"string_value\": \"hello\",\n" 839 + " \"struct_value\": {\n" 840 + " \"number_value\": 1234.0\n" 841 + " },\n" 842 + " \"list_value\": [1.125, null]\n" 843 + " }\n" 844 + "}", 845 toJsonString(message)); 846 assertRoundTripEquals(message); 847 848 builder = TestStruct.newBuilder(); 849 builder.setValue(Value.newBuilder().setNullValueValue(0).build()); 850 message = builder.build(); 851 assertEquals("{\n" + " \"value\": null\n" + "}", toJsonString(message)); 852 assertRoundTripEquals(message); 853 854 builder = TestStruct.newBuilder(); 855 listBuilder = builder.getListValueBuilder(); 856 listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build()); 857 listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build()); 858 message = builder.build(); 859 assertEquals("{\n" + " \"listValue\": [31831.125, null]\n" + "}", toJsonString(message)); 860 assertRoundTripEquals(message); 861 } 862 863 testAnyFieldsWithCustomAddedTypeRegistry()864 public void testAnyFieldsWithCustomAddedTypeRegistry() throws Exception { 865 TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build(); 866 TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build(); 867 868 com.google.protobuf.TypeRegistry registry = 869 com.google.protobuf.TypeRegistry.newBuilder().add(content.getDescriptorForType()).build(); 870 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 871 872 assertEquals( 873 "{\n" 874 + " \"anyValue\": {\n" 875 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 876 + " \"optionalInt32\": 1234\n" 877 + " }\n" 878 + "}", 879 printer.print(message)); 880 assertRoundTripEquals(message, registry); 881 882 TestAny messageWithDefaultAnyValue = 883 TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build(); 884 assertEquals("{\n" + " \"anyValue\": {}\n" + "}", printer.print(messageWithDefaultAnyValue)); 885 assertRoundTripEquals(messageWithDefaultAnyValue, registry); 886 887 // Well-known types have a special formatting when embedded in Any. 888 // 889 // 1. Any in Any. 890 Any anyMessage = Any.pack(Any.pack(content)); 891 assertEquals( 892 "{\n" 893 + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" 894 + " \"value\": {\n" 895 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 896 + " \"optionalInt32\": 1234\n" 897 + " }\n" 898 + "}", 899 printer.print(anyMessage)); 900 assertRoundTripEquals(anyMessage, registry); 901 } 902 testAnyFields()903 public void testAnyFields() throws Exception { 904 TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build(); 905 TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build(); 906 907 // A TypeRegistry must be provided in order to convert Any types. 908 try { 909 toJsonString(message); 910 fail("Exception is expected."); 911 } catch (IOException e) { 912 // Expected. 913 } 914 915 JsonFormat.TypeRegistry registry = 916 JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build(); 917 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 918 919 assertEquals( 920 "{\n" 921 + " \"anyValue\": {\n" 922 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 923 + " \"optionalInt32\": 1234\n" 924 + " }\n" 925 + "}", 926 printer.print(message)); 927 assertRoundTripEquals(message, registry); 928 929 TestAny messageWithDefaultAnyValue = 930 TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build(); 931 assertEquals( 932 "{\n" 933 + " \"anyValue\": {}\n" 934 + "}", 935 printer.print(messageWithDefaultAnyValue)); 936 assertRoundTripEquals(messageWithDefaultAnyValue, registry); 937 938 // Well-known types have a special formatting when embedded in Any. 939 // 940 // 1. Any in Any. 941 Any anyMessage = Any.pack(Any.pack(content)); 942 assertEquals( 943 "{\n" 944 + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" 945 + " \"value\": {\n" 946 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 947 + " \"optionalInt32\": 1234\n" 948 + " }\n" 949 + "}", 950 printer.print(anyMessage)); 951 assertRoundTripEquals(anyMessage, registry); 952 953 // 2. Wrappers in Any. 954 anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build()); 955 assertEquals( 956 "{\n" 957 + " \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n" 958 + " \"value\": 12345\n" 959 + "}", 960 printer.print(anyMessage)); 961 assertRoundTripEquals(anyMessage, registry); 962 anyMessage = Any.pack(UInt32Value.newBuilder().setValue(12345).build()); 963 assertEquals( 964 "{\n" 965 + " \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n" 966 + " \"value\": 12345\n" 967 + "}", 968 printer.print(anyMessage)); 969 assertRoundTripEquals(anyMessage, registry); 970 anyMessage = Any.pack(Int64Value.newBuilder().setValue(12345).build()); 971 assertEquals( 972 "{\n" 973 + " \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n" 974 + " \"value\": \"12345\"\n" 975 + "}", 976 printer.print(anyMessage)); 977 assertRoundTripEquals(anyMessage, registry); 978 anyMessage = Any.pack(UInt64Value.newBuilder().setValue(12345).build()); 979 assertEquals( 980 "{\n" 981 + " \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n" 982 + " \"value\": \"12345\"\n" 983 + "}", 984 printer.print(anyMessage)); 985 assertRoundTripEquals(anyMessage, registry); 986 anyMessage = Any.pack(FloatValue.newBuilder().setValue(12345).build()); 987 assertEquals( 988 "{\n" 989 + " \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n" 990 + " \"value\": 12345.0\n" 991 + "}", 992 printer.print(anyMessage)); 993 assertRoundTripEquals(anyMessage, registry); 994 anyMessage = Any.pack(DoubleValue.newBuilder().setValue(12345).build()); 995 assertEquals( 996 "{\n" 997 + " \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n" 998 + " \"value\": 12345.0\n" 999 + "}", 1000 printer.print(anyMessage)); 1001 assertRoundTripEquals(anyMessage, registry); 1002 anyMessage = Any.pack(BoolValue.newBuilder().setValue(true).build()); 1003 assertEquals( 1004 "{\n" 1005 + " \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n" 1006 + " \"value\": true\n" 1007 + "}", 1008 printer.print(anyMessage)); 1009 assertRoundTripEquals(anyMessage, registry); 1010 anyMessage = Any.pack(StringValue.newBuilder().setValue("Hello").build()); 1011 assertEquals( 1012 "{\n" 1013 + " \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n" 1014 + " \"value\": \"Hello\"\n" 1015 + "}", 1016 printer.print(anyMessage)); 1017 assertRoundTripEquals(anyMessage, registry); 1018 anyMessage = 1019 Any.pack(BytesValue.newBuilder().setValue(ByteString.copyFrom(new byte[] {1, 2})).build()); 1020 assertEquals( 1021 "{\n" 1022 + " \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n" 1023 + " \"value\": \"AQI=\"\n" 1024 + "}", 1025 printer.print(anyMessage)); 1026 assertRoundTripEquals(anyMessage, registry); 1027 1028 // 3. Timestamp in Any. 1029 anyMessage = Any.pack(Timestamps.parse("1969-12-31T23:59:59Z")); 1030 assertEquals( 1031 "{\n" 1032 + " \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n" 1033 + " \"value\": \"1969-12-31T23:59:59Z\"\n" 1034 + "}", 1035 printer.print(anyMessage)); 1036 assertRoundTripEquals(anyMessage, registry); 1037 1038 // 4. Duration in Any 1039 anyMessage = Any.pack(Durations.parse("12345.10s")); 1040 assertEquals( 1041 "{\n" 1042 + " \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n" 1043 + " \"value\": \"12345.100s\"\n" 1044 + "}", 1045 printer.print(anyMessage)); 1046 assertRoundTripEquals(anyMessage, registry); 1047 1048 // 5. FieldMask in Any 1049 anyMessage = Any.pack(FieldMaskUtil.fromString("foo.bar,baz")); 1050 assertEquals( 1051 "{\n" 1052 + " \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n" 1053 + " \"value\": \"foo.bar,baz\"\n" 1054 + "}", 1055 printer.print(anyMessage)); 1056 assertRoundTripEquals(anyMessage, registry); 1057 1058 // 6. Struct in Any 1059 Struct.Builder structBuilder = Struct.newBuilder(); 1060 structBuilder.putFields("number", Value.newBuilder().setNumberValue(1.125).build()); 1061 anyMessage = Any.pack(structBuilder.build()); 1062 assertEquals( 1063 "{\n" 1064 + " \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n" 1065 + " \"value\": {\n" 1066 + " \"number\": 1.125\n" 1067 + " }\n" 1068 + "}", 1069 printer.print(anyMessage)); 1070 assertRoundTripEquals(anyMessage, registry); 1071 1072 // 7. Value (number type) in Any 1073 Value.Builder valueBuilder = Value.newBuilder(); 1074 valueBuilder.setNumberValue(1); 1075 anyMessage = Any.pack(valueBuilder.build()); 1076 assertEquals( 1077 "{\n" 1078 + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" 1079 + " \"value\": 1.0\n" 1080 + "}", 1081 printer.print(anyMessage)); 1082 assertRoundTripEquals(anyMessage, registry); 1083 1084 // 8. Value (null type) in Any 1085 anyMessage = Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build()); 1086 assertEquals( 1087 "{\n" 1088 + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" 1089 + " \"value\": null\n" 1090 + "}", 1091 printer.print(anyMessage)); 1092 assertRoundTripEquals(anyMessage, registry); 1093 } 1094 testAnyInMaps()1095 public void testAnyInMaps() throws Exception { 1096 JsonFormat.TypeRegistry registry = 1097 JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build(); 1098 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 1099 1100 TestAny.Builder testAny = TestAny.newBuilder(); 1101 testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.newBuilder().setValue(123).build())); 1102 testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.newBuilder().setValue(456).build())); 1103 testAny.putAnyMap("timestamp", Any.pack(Timestamps.parse("1969-12-31T23:59:59Z"))); 1104 testAny.putAnyMap("duration", Any.pack(Durations.parse("12345.1s"))); 1105 testAny.putAnyMap("field_mask", Any.pack(FieldMaskUtil.fromString("foo.bar,baz"))); 1106 Value numberValue = Value.newBuilder().setNumberValue(1.125).build(); 1107 Struct.Builder struct = Struct.newBuilder(); 1108 struct.putFields("number", numberValue); 1109 testAny.putAnyMap("struct", Any.pack(struct.build())); 1110 Value nullValue = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(); 1111 testAny.putAnyMap( 1112 "list_value", 1113 Any.pack(ListValue.newBuilder().addValues(numberValue).addValues(nullValue).build())); 1114 testAny.putAnyMap("number_value", Any.pack(numberValue)); 1115 testAny.putAnyMap("any_value_number", Any.pack(Any.pack(numberValue))); 1116 testAny.putAnyMap("any_value_default", Any.pack(Any.getDefaultInstance())); 1117 testAny.putAnyMap("default", Any.getDefaultInstance()); 1118 1119 assertEquals( 1120 "{\n" 1121 + " \"anyMap\": {\n" 1122 + " \"int32_wrapper\": {\n" 1123 + " \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n" 1124 + " \"value\": 123\n" 1125 + " },\n" 1126 + " \"int64_wrapper\": {\n" 1127 + " \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n" 1128 + " \"value\": \"456\"\n" 1129 + " },\n" 1130 + " \"timestamp\": {\n" 1131 + " \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n" 1132 + " \"value\": \"1969-12-31T23:59:59Z\"\n" 1133 + " },\n" 1134 + " \"duration\": {\n" 1135 + " \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n" 1136 + " \"value\": \"12345.100s\"\n" 1137 + " },\n" 1138 + " \"field_mask\": {\n" 1139 + " \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n" 1140 + " \"value\": \"foo.bar,baz\"\n" 1141 + " },\n" 1142 + " \"struct\": {\n" 1143 + " \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n" 1144 + " \"value\": {\n" 1145 + " \"number\": 1.125\n" 1146 + " }\n" 1147 + " },\n" 1148 + " \"list_value\": {\n" 1149 + " \"@type\": \"type.googleapis.com/google.protobuf.ListValue\",\n" 1150 + " \"value\": [1.125, null]\n" 1151 + " },\n" 1152 + " \"number_value\": {\n" 1153 + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" 1154 + " \"value\": 1.125\n" 1155 + " },\n" 1156 + " \"any_value_number\": {\n" 1157 + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" 1158 + " \"value\": {\n" 1159 + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" 1160 + " \"value\": 1.125\n" 1161 + " }\n" 1162 + " },\n" 1163 + " \"any_value_default\": {\n" 1164 + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" 1165 + " \"value\": {}\n" 1166 + " },\n" 1167 + " \"default\": {}\n" 1168 + " }\n" 1169 + "}", 1170 printer.print(testAny.build())); 1171 assertRoundTripEquals(testAny.build(), registry); 1172 } 1173 testParserMissingTypeUrl()1174 public void testParserMissingTypeUrl() throws Exception { 1175 try { 1176 Any.Builder builder = Any.newBuilder(); 1177 mergeFromJson("{\n" + " \"optionalInt32\": 1234\n" + "}", builder); 1178 fail("Exception is expected."); 1179 } catch (IOException e) { 1180 // Expected. 1181 } 1182 } 1183 testParserUnexpectedTypeUrl()1184 public void testParserUnexpectedTypeUrl() throws Exception { 1185 try { 1186 Any.Builder builder = Any.newBuilder(); 1187 mergeFromJson( 1188 "{\n" 1189 + " \"@type\": \"type.googleapis.com/json_test.UnexpectedTypes\",\n" 1190 + " \"optionalInt32\": 12345\n" 1191 + "}", 1192 builder); 1193 fail("Exception is expected."); 1194 } catch (IOException e) { 1195 // Expected. 1196 } 1197 } 1198 testParserRejectTrailingComma()1199 public void testParserRejectTrailingComma() throws Exception { 1200 try { 1201 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1202 mergeFromJson("{\n" + " \"optionalInt32\": 12345,\n" + "}", builder); 1203 fail("Exception is expected."); 1204 } catch (IOException e) { 1205 // Expected. 1206 } 1207 1208 // TODO(xiaofeng): GSON allows trailing comma in arrays even after I set 1209 // the JsonReader to non-lenient mode. If we want to enforce strict JSON 1210 // compliance, we might want to switch to a different JSON parser or 1211 // implement one by ourselves. 1212 // try { 1213 // TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1214 // JsonFormat.merge( 1215 // "{\n" 1216 // + " \"repeatedInt32\": [12345,]\n" 1217 // + "}", builder); 1218 // fail("Exception is expected."); 1219 // } catch (IOException e) { 1220 // // Expected. 1221 // } 1222 } 1223 testParserRejectInvalidBase64()1224 public void testParserRejectInvalidBase64() throws Exception { 1225 assertRejects("optionalBytes", "!@#$"); 1226 } 1227 testParserAcceptBase64Variants()1228 public void testParserAcceptBase64Variants() throws Exception { 1229 assertAccepts("optionalBytes", "AQI"); // No padding 1230 assertAccepts("optionalBytes", "-_w"); // base64Url, no padding 1231 } 1232 testParserRejectInvalidEnumValue()1233 public void testParserRejectInvalidEnumValue() throws Exception { 1234 try { 1235 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1236 mergeFromJson("{\n" + " \"optionalNestedEnum\": \"XXX\"\n" + "}", builder); 1237 fail("Exception is expected."); 1238 } catch (InvalidProtocolBufferException e) { 1239 // Expected. 1240 } 1241 } 1242 testParserUnknownFields()1243 public void testParserUnknownFields() throws Exception { 1244 try { 1245 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1246 String json = "{\n" + " \"unknownField\": \"XXX\"\n" + "}"; 1247 JsonFormat.parser().merge(json, builder); 1248 fail("Exception is expected."); 1249 } catch (InvalidProtocolBufferException e) { 1250 // Expected. 1251 } 1252 } 1253 testParserIgnoringUnknownFields()1254 public void testParserIgnoringUnknownFields() throws Exception { 1255 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1256 String json = "{\n" + " \"unknownField\": \"XXX\"\n" + "}"; 1257 JsonFormat.parser().ignoringUnknownFields().merge(json, builder); 1258 } 1259 testParserIgnoringUnknownEnums()1260 public void testParserIgnoringUnknownEnums() throws Exception { 1261 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1262 String json = "{\n" + " \"optionalNestedEnum\": \"XXX\"\n" + "}"; 1263 JsonFormat.parser().ignoringUnknownFields().merge(json, builder); 1264 assertEquals(0, builder.getOptionalNestedEnumValue()); 1265 } 1266 testParserSupportAliasEnums()1267 public void testParserSupportAliasEnums() throws Exception { 1268 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1269 String json = "{\n" + " \"optionalAliasedEnum\": \"QUX\"\n" + "}"; 1270 JsonFormat.parser().merge(json, builder); 1271 assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum()); 1272 1273 builder = TestAllTypes.newBuilder(); 1274 json = "{\n" + " \"optionalAliasedEnum\": \"qux\"\n" + "}"; 1275 JsonFormat.parser().merge(json, builder); 1276 assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum()); 1277 1278 builder = TestAllTypes.newBuilder(); 1279 json = "{\n" + " \"optionalAliasedEnum\": \"bAz\"\n" + "}"; 1280 JsonFormat.parser().merge(json, builder); 1281 assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum()); 1282 } 1283 testUnknownEnumMap()1284 public void testUnknownEnumMap() throws Exception { 1285 TestMap.Builder builder = TestMap.newBuilder(); 1286 JsonFormat.parser() 1287 .ignoringUnknownFields() 1288 .merge("{\n" + " \"int32ToEnumMap\": {1: XXX, 2: FOO}" + "}", builder); 1289 1290 assertEquals(NestedEnum.FOO, builder.getInt32ToEnumMapMap().get(2)); 1291 assertEquals(1, builder.getInt32ToEnumMapMap().size()); 1292 } 1293 testRepeatedUnknownEnum()1294 public void testRepeatedUnknownEnum() throws Exception { 1295 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1296 JsonFormat.parser() 1297 .ignoringUnknownFields() 1298 .merge("{\n" + " \"repeatedNestedEnum\": [XXX, FOO, BAR, BAZ]" + "}", builder); 1299 1300 assertEquals(NestedEnum.FOO, builder.getRepeatedNestedEnum(0)); 1301 assertEquals(NestedEnum.BAR, builder.getRepeatedNestedEnum(1)); 1302 assertEquals(NestedEnum.BAZ, builder.getRepeatedNestedEnum(2)); 1303 assertEquals(3, builder.getRepeatedNestedEnumList().size()); 1304 } 1305 testParserIntegerEnumValue()1306 public void testParserIntegerEnumValue() throws Exception { 1307 TestAllTypes.Builder actualBuilder = TestAllTypes.newBuilder(); 1308 mergeFromJson("{\n" + " \"optionalNestedEnum\": 2\n" + "}", actualBuilder); 1309 1310 TestAllTypes expected = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAZ).build(); 1311 assertEquals(expected, actualBuilder.build()); 1312 } 1313 testCustomJsonName()1314 public void testCustomJsonName() throws Exception { 1315 TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build(); 1316 assertEquals("{\n" + " \"@value\": 12345\n" + "}", JsonFormat.printer().print(message)); 1317 assertRoundTripEquals(message); 1318 } 1319 1320 // Regression test for b/73832901. Make sure html tags are escaped. testHtmlEscape()1321 public void testHtmlEscape() throws Exception { 1322 TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("</script>").build(); 1323 assertEquals("{\n \"optionalString\": \"\\u003c/script\\u003e\"\n}", toJsonString(message)); 1324 1325 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1326 JsonFormat.parser().merge(toJsonString(message), builder); 1327 assertEquals(message.getOptionalString(), builder.getOptionalString()); 1328 } 1329 testIncludingDefaultValueFields()1330 public void testIncludingDefaultValueFields() throws Exception { 1331 TestAllTypes message = TestAllTypes.getDefaultInstance(); 1332 assertEquals("{\n}", JsonFormat.printer().print(message)); 1333 assertEquals( 1334 "{\n" 1335 + " \"optionalInt32\": 0,\n" 1336 + " \"optionalInt64\": \"0\",\n" 1337 + " \"optionalUint32\": 0,\n" 1338 + " \"optionalUint64\": \"0\",\n" 1339 + " \"optionalSint32\": 0,\n" 1340 + " \"optionalSint64\": \"0\",\n" 1341 + " \"optionalFixed32\": 0,\n" 1342 + " \"optionalFixed64\": \"0\",\n" 1343 + " \"optionalSfixed32\": 0,\n" 1344 + " \"optionalSfixed64\": \"0\",\n" 1345 + " \"optionalFloat\": 0.0,\n" 1346 + " \"optionalDouble\": 0.0,\n" 1347 + " \"optionalBool\": false,\n" 1348 + " \"optionalString\": \"\",\n" 1349 + " \"optionalBytes\": \"\",\n" 1350 + " \"optionalNestedEnum\": \"FOO\",\n" 1351 + " \"repeatedInt32\": [],\n" 1352 + " \"repeatedInt64\": [],\n" 1353 + " \"repeatedUint32\": [],\n" 1354 + " \"repeatedUint64\": [],\n" 1355 + " \"repeatedSint32\": [],\n" 1356 + " \"repeatedSint64\": [],\n" 1357 + " \"repeatedFixed32\": [],\n" 1358 + " \"repeatedFixed64\": [],\n" 1359 + " \"repeatedSfixed32\": [],\n" 1360 + " \"repeatedSfixed64\": [],\n" 1361 + " \"repeatedFloat\": [],\n" 1362 + " \"repeatedDouble\": [],\n" 1363 + " \"repeatedBool\": [],\n" 1364 + " \"repeatedString\": [],\n" 1365 + " \"repeatedBytes\": [],\n" 1366 + " \"repeatedNestedMessage\": [],\n" 1367 + " \"repeatedNestedEnum\": [],\n" 1368 + " \"optionalAliasedEnum\": \"ALIAS_FOO\"\n" 1369 + "}", 1370 JsonFormat.printer().includingDefaultValueFields().print(message)); 1371 1372 Set<FieldDescriptor> fixedFields = new HashSet<FieldDescriptor>(); 1373 for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) { 1374 if (fieldDesc.getName().contains("_fixed")) { 1375 fixedFields.add(fieldDesc); 1376 } 1377 } 1378 1379 assertEquals( 1380 "{\n" 1381 + " \"optionalFixed32\": 0,\n" 1382 + " \"optionalFixed64\": \"0\",\n" 1383 + " \"repeatedFixed32\": [],\n" 1384 + " \"repeatedFixed64\": []\n" 1385 + "}", 1386 JsonFormat.printer().includingDefaultValueFields(fixedFields).print(message)); 1387 1388 TestAllTypes messageNonDefaults = 1389 message.toBuilder().setOptionalInt64(1234).setOptionalFixed32(3232).build(); 1390 assertEquals( 1391 "{\n" 1392 + " \"optionalInt64\": \"1234\",\n" 1393 + " \"optionalFixed32\": 3232,\n" 1394 + " \"optionalFixed64\": \"0\",\n" 1395 + " \"repeatedFixed32\": [],\n" 1396 + " \"repeatedFixed64\": []\n" 1397 + "}", 1398 JsonFormat.printer().includingDefaultValueFields(fixedFields).print(messageNonDefaults)); 1399 1400 try { 1401 JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields(); 1402 fail("IllegalStateException is expected."); 1403 } catch (IllegalStateException e) { 1404 // Expected. 1405 assertTrue( 1406 "Exception message should mention includingDefaultValueFields.", 1407 e.getMessage().contains("includingDefaultValueFields")); 1408 } 1409 1410 try { 1411 JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields(fixedFields); 1412 fail("IllegalStateException is expected."); 1413 } catch (IllegalStateException e) { 1414 // Expected. 1415 assertTrue( 1416 "Exception message should mention includingDefaultValueFields.", 1417 e.getMessage().contains("includingDefaultValueFields")); 1418 } 1419 1420 try { 1421 JsonFormat.printer().includingDefaultValueFields(fixedFields).includingDefaultValueFields(); 1422 fail("IllegalStateException is expected."); 1423 } catch (IllegalStateException e) { 1424 // Expected. 1425 assertTrue( 1426 "Exception message should mention includingDefaultValueFields.", 1427 e.getMessage().contains("includingDefaultValueFields")); 1428 } 1429 1430 try { 1431 JsonFormat.printer() 1432 .includingDefaultValueFields(fixedFields) 1433 .includingDefaultValueFields(fixedFields); 1434 fail("IllegalStateException is expected."); 1435 } catch (IllegalStateException e) { 1436 // Expected. 1437 assertTrue( 1438 "Exception message should mention includingDefaultValueFields.", 1439 e.getMessage().contains("includingDefaultValueFields")); 1440 } 1441 1442 Set<FieldDescriptor> intFields = new HashSet<FieldDescriptor>(); 1443 for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) { 1444 if (fieldDesc.getName().contains("_int")) { 1445 intFields.add(fieldDesc); 1446 } 1447 } 1448 1449 try { 1450 JsonFormat.printer() 1451 .includingDefaultValueFields(intFields) 1452 .includingDefaultValueFields(fixedFields); 1453 fail("IllegalStateException is expected."); 1454 } catch (IllegalStateException e) { 1455 // Expected. 1456 assertTrue( 1457 "Exception message should mention includingDefaultValueFields.", 1458 e.getMessage().contains("includingDefaultValueFields")); 1459 } 1460 1461 try { 1462 JsonFormat.printer().includingDefaultValueFields(null); 1463 fail("IllegalArgumentException is expected."); 1464 } catch (IllegalArgumentException e) { 1465 // Expected. 1466 assertTrue( 1467 "Exception message should mention includingDefaultValueFields.", 1468 e.getMessage().contains("includingDefaultValueFields")); 1469 } 1470 1471 try { 1472 JsonFormat.printer().includingDefaultValueFields(Collections.<FieldDescriptor>emptySet()); 1473 fail("IllegalArgumentException is expected."); 1474 } catch (IllegalArgumentException e) { 1475 // Expected. 1476 assertTrue( 1477 "Exception message should mention includingDefaultValueFields.", 1478 e.getMessage().contains("includingDefaultValueFields")); 1479 } 1480 1481 TestMap mapMessage = TestMap.getDefaultInstance(); 1482 assertEquals("{\n}", JsonFormat.printer().print(mapMessage)); 1483 assertEquals( 1484 "{\n" 1485 + " \"int32ToInt32Map\": {\n" 1486 + " },\n" 1487 + " \"int64ToInt32Map\": {\n" 1488 + " },\n" 1489 + " \"uint32ToInt32Map\": {\n" 1490 + " },\n" 1491 + " \"uint64ToInt32Map\": {\n" 1492 + " },\n" 1493 + " \"sint32ToInt32Map\": {\n" 1494 + " },\n" 1495 + " \"sint64ToInt32Map\": {\n" 1496 + " },\n" 1497 + " \"fixed32ToInt32Map\": {\n" 1498 + " },\n" 1499 + " \"fixed64ToInt32Map\": {\n" 1500 + " },\n" 1501 + " \"sfixed32ToInt32Map\": {\n" 1502 + " },\n" 1503 + " \"sfixed64ToInt32Map\": {\n" 1504 + " },\n" 1505 + " \"boolToInt32Map\": {\n" 1506 + " },\n" 1507 + " \"stringToInt32Map\": {\n" 1508 + " },\n" 1509 + " \"int32ToInt64Map\": {\n" 1510 + " },\n" 1511 + " \"int32ToUint32Map\": {\n" 1512 + " },\n" 1513 + " \"int32ToUint64Map\": {\n" 1514 + " },\n" 1515 + " \"int32ToSint32Map\": {\n" 1516 + " },\n" 1517 + " \"int32ToSint64Map\": {\n" 1518 + " },\n" 1519 + " \"int32ToFixed32Map\": {\n" 1520 + " },\n" 1521 + " \"int32ToFixed64Map\": {\n" 1522 + " },\n" 1523 + " \"int32ToSfixed32Map\": {\n" 1524 + " },\n" 1525 + " \"int32ToSfixed64Map\": {\n" 1526 + " },\n" 1527 + " \"int32ToFloatMap\": {\n" 1528 + " },\n" 1529 + " \"int32ToDoubleMap\": {\n" 1530 + " },\n" 1531 + " \"int32ToBoolMap\": {\n" 1532 + " },\n" 1533 + " \"int32ToStringMap\": {\n" 1534 + " },\n" 1535 + " \"int32ToBytesMap\": {\n" 1536 + " },\n" 1537 + " \"int32ToMessageMap\": {\n" 1538 + " },\n" 1539 + " \"int32ToEnumMap\": {\n" 1540 + " }\n" 1541 + "}", 1542 JsonFormat.printer().includingDefaultValueFields().print(mapMessage)); 1543 1544 TestOneof oneofMessage = TestOneof.getDefaultInstance(); 1545 assertEquals("{\n}", JsonFormat.printer().print(oneofMessage)); 1546 assertEquals("{\n}", JsonFormat.printer().includingDefaultValueFields().print(oneofMessage)); 1547 1548 oneofMessage = TestOneof.newBuilder().setOneofInt32(42).build(); 1549 assertEquals("{\n \"oneofInt32\": 42\n}", JsonFormat.printer().print(oneofMessage)); 1550 assertEquals( 1551 "{\n \"oneofInt32\": 42\n}", 1552 JsonFormat.printer().includingDefaultValueFields().print(oneofMessage)); 1553 1554 TestOneof.Builder oneofBuilder = TestOneof.newBuilder(); 1555 mergeFromJson("{\n" + " \"oneofNullValue\": null \n" + "}", oneofBuilder); 1556 oneofMessage = oneofBuilder.build(); 1557 assertEquals("{\n \"oneofNullValue\": null\n}", JsonFormat.printer().print(oneofMessage)); 1558 assertEquals( 1559 "{\n \"oneofNullValue\": null\n}", 1560 JsonFormat.printer().includingDefaultValueFields().print(oneofMessage)); 1561 } 1562 testPreservingProtoFieldNames()1563 public void testPreservingProtoFieldNames() throws Exception { 1564 TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build(); 1565 assertEquals("{\n" + " \"optionalInt32\": 12345\n" + "}", JsonFormat.printer().print(message)); 1566 assertEquals( 1567 "{\n" + " \"optional_int32\": 12345\n" + "}", 1568 JsonFormat.printer().preservingProtoFieldNames().print(message)); 1569 1570 // The json_name field option is ignored when configured to use original proto field names. 1571 TestCustomJsonName messageWithCustomJsonName = 1572 TestCustomJsonName.newBuilder().setValue(12345).build(); 1573 assertEquals( 1574 "{\n" + " \"value\": 12345\n" + "}", 1575 JsonFormat.printer().preservingProtoFieldNames().print(messageWithCustomJsonName)); 1576 1577 // Parsers accept both original proto field names and lowerCamelCase names. 1578 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1579 JsonFormat.parser().merge("{\"optionalInt32\": 12345}", builder); 1580 assertEquals(12345, builder.getOptionalInt32()); 1581 builder.clear(); 1582 JsonFormat.parser().merge("{\"optional_int32\": 54321}", builder); 1583 assertEquals(54321, builder.getOptionalInt32()); 1584 } 1585 testPrintingEnumsAsInts()1586 public void testPrintingEnumsAsInts() throws Exception { 1587 TestAllTypes message = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build(); 1588 assertEquals( 1589 "{\n" + " \"optionalNestedEnum\": 1\n" + "}", 1590 JsonFormat.printer().printingEnumsAsInts().print(message)); 1591 } 1592 testOmittingInsignificantWhiteSpace()1593 public void testOmittingInsignificantWhiteSpace() throws Exception { 1594 TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build(); 1595 assertEquals( 1596 "{" + "\"optionalInt32\":12345" + "}", 1597 JsonFormat.printer().omittingInsignificantWhitespace().print(message)); 1598 TestAllTypes message1 = TestAllTypes.getDefaultInstance(); 1599 assertEquals("{}", JsonFormat.printer().omittingInsignificantWhitespace().print(message1)); 1600 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1601 setAllFields(builder); 1602 TestAllTypes message2 = builder.build(); 1603 assertEquals( 1604 "{" 1605 + "\"optionalInt32\":1234," 1606 + "\"optionalInt64\":\"1234567890123456789\"," 1607 + "\"optionalUint32\":5678," 1608 + "\"optionalUint64\":\"2345678901234567890\"," 1609 + "\"optionalSint32\":9012," 1610 + "\"optionalSint64\":\"3456789012345678901\"," 1611 + "\"optionalFixed32\":3456," 1612 + "\"optionalFixed64\":\"4567890123456789012\"," 1613 + "\"optionalSfixed32\":7890," 1614 + "\"optionalSfixed64\":\"5678901234567890123\"," 1615 + "\"optionalFloat\":1.5," 1616 + "\"optionalDouble\":1.25," 1617 + "\"optionalBool\":true," 1618 + "\"optionalString\":\"Hello world!\"," 1619 + "\"optionalBytes\":\"AAEC\"," 1620 + "\"optionalNestedMessage\":{" 1621 + "\"value\":100" 1622 + "}," 1623 + "\"optionalNestedEnum\":\"BAR\"," 1624 + "\"repeatedInt32\":[1234,234]," 1625 + "\"repeatedInt64\":[\"1234567890123456789\",\"234567890123456789\"]," 1626 + "\"repeatedUint32\":[5678,678]," 1627 + "\"repeatedUint64\":[\"2345678901234567890\",\"345678901234567890\"]," 1628 + "\"repeatedSint32\":[9012,10]," 1629 + "\"repeatedSint64\":[\"3456789012345678901\",\"456789012345678901\"]," 1630 + "\"repeatedFixed32\":[3456,456]," 1631 + "\"repeatedFixed64\":[\"4567890123456789012\",\"567890123456789012\"]," 1632 + "\"repeatedSfixed32\":[7890,890]," 1633 + "\"repeatedSfixed64\":[\"5678901234567890123\",\"678901234567890123\"]," 1634 + "\"repeatedFloat\":[1.5,11.5]," 1635 + "\"repeatedDouble\":[1.25,11.25]," 1636 + "\"repeatedBool\":[true,true]," 1637 + "\"repeatedString\":[\"Hello world!\",\"ello world!\"]," 1638 + "\"repeatedBytes\":[\"AAEC\",\"AQI=\"]," 1639 + "\"repeatedNestedMessage\":[{" 1640 + "\"value\":100" 1641 + "},{" 1642 + "\"value\":200" 1643 + "}]," 1644 + "\"repeatedNestedEnum\":[\"BAR\",\"BAZ\"]" 1645 + "}", 1646 toCompactJsonString(message2)); 1647 } 1648 1649 // Regression test for b/29892357 testEmptyWrapperTypesInAny()1650 public void testEmptyWrapperTypesInAny() throws Exception { 1651 JsonFormat.TypeRegistry registry = 1652 JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build(); 1653 JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry); 1654 1655 Any.Builder builder = Any.newBuilder(); 1656 parser.merge( 1657 "{\n" 1658 + " \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n" 1659 + " \"value\": false\n" 1660 + "}\n", 1661 builder); 1662 Any any = builder.build(); 1663 assertEquals(0, any.getValue().size()); 1664 } 1665 testRecursionLimit()1666 public void testRecursionLimit() throws Exception { 1667 String input = 1668 "{\n" 1669 + " \"nested\": {\n" 1670 + " \"nested\": {\n" 1671 + " \"nested\": {\n" 1672 + " \"nested\": {\n" 1673 + " \"value\": 1234\n" 1674 + " }\n" 1675 + " }\n" 1676 + " }\n" 1677 + " }\n" 1678 + "}\n"; 1679 1680 JsonFormat.Parser parser = JsonFormat.parser(); 1681 TestRecursive.Builder builder = TestRecursive.newBuilder(); 1682 parser.merge(input, builder); 1683 TestRecursive message = builder.build(); 1684 assertEquals(1234, message.getNested().getNested().getNested().getNested().getValue()); 1685 1686 parser = JsonFormat.parser().usingRecursionLimit(3); 1687 builder = TestRecursive.newBuilder(); 1688 try { 1689 parser.merge(input, builder); 1690 fail("Exception is expected."); 1691 } catch (InvalidProtocolBufferException e) { 1692 // Expected. 1693 } 1694 } 1695 1696 // Test that we are not leaking out JSON exceptions. testJsonException()1697 public void testJsonException() throws Exception { 1698 InputStream throwingInputStream = 1699 new InputStream() { 1700 public int read() throws IOException { 1701 throw new IOException("12345"); 1702 } 1703 }; 1704 InputStreamReader throwingReader = new InputStreamReader(throwingInputStream); 1705 // When the underlying reader throws IOException, JsonFormat should forward 1706 // through this IOException. 1707 try { 1708 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1709 JsonFormat.parser().merge(throwingReader, builder); 1710 fail("Exception is expected."); 1711 } catch (IOException e) { 1712 assertEquals("12345", e.getMessage()); 1713 } 1714 1715 Reader invalidJsonReader = new StringReader("{ xxx - yyy }"); 1716 // When the JSON parser throws parser exceptions, JsonFormat should turn 1717 // that into InvalidProtocolBufferException. 1718 try { 1719 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1720 JsonFormat.parser().merge(invalidJsonReader, builder); 1721 fail("Exception is expected."); 1722 } catch (InvalidProtocolBufferException e) { 1723 // Expected. 1724 } 1725 } 1726 1727 // Test that an error is thrown if a nested JsonObject is parsed as a primitive field. testJsonObjectForPrimitiveField()1728 public void testJsonObjectForPrimitiveField() throws Exception { 1729 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1730 try { 1731 mergeFromJson( 1732 "{\n" 1733 + " \"optionalString\": {\n" 1734 + " \"invalidNestedString\": \"Hello world\"\n" 1735 + " }\n" 1736 + "}\n", 1737 builder); 1738 } catch (InvalidProtocolBufferException e) { 1739 // Expected. 1740 } 1741 } 1742 testSortedMapKeys()1743 public void testSortedMapKeys() throws Exception { 1744 TestMap.Builder mapBuilder = TestMap.newBuilder(); 1745 mapBuilder.putStringToInt32Map("\ud834\udd20", 3); // utf-8 F0 9D 84 A0 1746 mapBuilder.putStringToInt32Map("foo", 99); 1747 mapBuilder.putStringToInt32Map("xxx", 123); 1748 mapBuilder.putStringToInt32Map("\u20ac", 1); // utf-8 E2 82 AC 1749 mapBuilder.putStringToInt32Map("abc", 20); 1750 mapBuilder.putStringToInt32Map("19", 19); 1751 mapBuilder.putStringToInt32Map("8", 8); 1752 mapBuilder.putStringToInt32Map("\ufb00", 2); // utf-8 EF AC 80 1753 mapBuilder.putInt32ToInt32Map(3, 3); 1754 mapBuilder.putInt32ToInt32Map(10, 10); 1755 mapBuilder.putInt32ToInt32Map(5, 5); 1756 mapBuilder.putInt32ToInt32Map(4, 4); 1757 mapBuilder.putInt32ToInt32Map(1, 1); 1758 mapBuilder.putInt32ToInt32Map(2, 2); 1759 mapBuilder.putInt32ToInt32Map(-3, -3); 1760 TestMap mapMessage = mapBuilder.build(); 1761 assertEquals( 1762 "{\n" 1763 + " \"int32ToInt32Map\": {\n" 1764 + " \"-3\": -3,\n" 1765 + " \"1\": 1,\n" 1766 + " \"2\": 2,\n" 1767 + " \"3\": 3,\n" 1768 + " \"4\": 4,\n" 1769 + " \"5\": 5,\n" 1770 + " \"10\": 10\n" 1771 + " },\n" 1772 + " \"stringToInt32Map\": {\n" 1773 + " \"19\": 19,\n" 1774 + " \"8\": 8,\n" 1775 + " \"abc\": 20,\n" 1776 + " \"foo\": 99,\n" 1777 + " \"xxx\": 123,\n" 1778 + " \"\u20ac\": 1,\n" 1779 + " \"\ufb00\": 2,\n" 1780 + " \"\ud834\udd20\": 3\n" 1781 + " }\n" 1782 + "}", 1783 toSortedJsonString(mapMessage)); 1784 1785 TestMap emptyMap = TestMap.getDefaultInstance(); 1786 assertEquals("{\n}", toSortedJsonString(emptyMap)); 1787 } 1788 testPrintingEnumsAsIntsChainedAfterIncludingDefaultValueFields()1789 public void testPrintingEnumsAsIntsChainedAfterIncludingDefaultValueFields() throws Exception { 1790 TestAllTypes message = TestAllTypes.newBuilder().setOptionalBool(false).build(); 1791 1792 assertEquals( 1793 "{\n" + " \"optionalBool\": false\n" + "}", 1794 JsonFormat.printer() 1795 .includingDefaultValueFields( 1796 ImmutableSet.of(message.getDescriptorForType().findFieldByName("optional_bool"))) 1797 .printingEnumsAsInts() 1798 .print(message)); 1799 } 1800 } 1801