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