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.DoubleValue; 38 import com.google.protobuf.FloatValue; 39 import com.google.protobuf.Int32Value; 40 import com.google.protobuf.Int64Value; 41 import com.google.protobuf.InvalidProtocolBufferException; 42 import com.google.protobuf.ListValue; 43 import com.google.protobuf.Message; 44 import com.google.protobuf.StringValue; 45 import com.google.protobuf.Struct; 46 import com.google.protobuf.UInt32Value; 47 import com.google.protobuf.UInt64Value; 48 import com.google.protobuf.Value; 49 import com.google.protobuf.util.JsonFormat.TypeRegistry; 50 import com.google.protobuf.util.JsonTestProto.TestAllTypes; 51 import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedEnum; 52 import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedMessage; 53 import com.google.protobuf.util.JsonTestProto.TestAny; 54 import com.google.protobuf.util.JsonTestProto.TestCustomJsonName; 55 import com.google.protobuf.util.JsonTestProto.TestDuration; 56 import com.google.protobuf.util.JsonTestProto.TestFieldMask; 57 import com.google.protobuf.util.JsonTestProto.TestMap; 58 import com.google.protobuf.util.JsonTestProto.TestOneof; 59 import com.google.protobuf.util.JsonTestProto.TestStruct; 60 import com.google.protobuf.util.JsonTestProto.TestTimestamp; 61 import com.google.protobuf.util.JsonTestProto.TestWrappers; 62 63 import junit.framework.TestCase; 64 65 import java.io.IOException; 66 import java.math.BigDecimal; 67 import java.math.BigInteger; 68 69 public class JsonFormatTest extends TestCase { setAllFields(TestAllTypes.Builder builder)70 private void setAllFields(TestAllTypes.Builder builder) { 71 builder.setOptionalInt32(1234); 72 builder.setOptionalInt64(1234567890123456789L); 73 builder.setOptionalUint32(5678); 74 builder.setOptionalUint64(2345678901234567890L); 75 builder.setOptionalSint32(9012); 76 builder.setOptionalSint64(3456789012345678901L); 77 builder.setOptionalFixed32(3456); 78 builder.setOptionalFixed64(4567890123456789012L); 79 builder.setOptionalSfixed32(7890); 80 builder.setOptionalSfixed64(5678901234567890123L); 81 builder.setOptionalFloat(1.5f); 82 builder.setOptionalDouble(1.25); 83 builder.setOptionalBool(true); 84 builder.setOptionalString("Hello world!"); 85 builder.setOptionalBytes(ByteString.copyFrom(new byte[]{0, 1, 2})); 86 builder.setOptionalNestedEnum(NestedEnum.BAR); 87 builder.getOptionalNestedMessageBuilder().setValue(100); 88 89 builder.addRepeatedInt32(1234); 90 builder.addRepeatedInt64(1234567890123456789L); 91 builder.addRepeatedUint32(5678); 92 builder.addRepeatedUint64(2345678901234567890L); 93 builder.addRepeatedSint32(9012); 94 builder.addRepeatedSint64(3456789012345678901L); 95 builder.addRepeatedFixed32(3456); 96 builder.addRepeatedFixed64(4567890123456789012L); 97 builder.addRepeatedSfixed32(7890); 98 builder.addRepeatedSfixed64(5678901234567890123L); 99 builder.addRepeatedFloat(1.5f); 100 builder.addRepeatedDouble(1.25); 101 builder.addRepeatedBool(true); 102 builder.addRepeatedString("Hello world!"); 103 builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{0, 1, 2})); 104 builder.addRepeatedNestedEnum(NestedEnum.BAR); 105 builder.addRepeatedNestedMessageBuilder().setValue(100); 106 107 builder.addRepeatedInt32(234); 108 builder.addRepeatedInt64(234567890123456789L); 109 builder.addRepeatedUint32(678); 110 builder.addRepeatedUint64(345678901234567890L); 111 builder.addRepeatedSint32(012); 112 builder.addRepeatedSint64(456789012345678901L); 113 builder.addRepeatedFixed32(456); 114 builder.addRepeatedFixed64(567890123456789012L); 115 builder.addRepeatedSfixed32(890); 116 builder.addRepeatedSfixed64(678901234567890123L); 117 builder.addRepeatedFloat(11.5f); 118 builder.addRepeatedDouble(11.25); 119 builder.addRepeatedBool(true); 120 builder.addRepeatedString("ello world!"); 121 builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{1, 2})); 122 builder.addRepeatedNestedEnum(NestedEnum.BAZ); 123 builder.addRepeatedNestedMessageBuilder().setValue(200); 124 } 125 assertRoundTripEquals(Message message)126 private void assertRoundTripEquals(Message message) throws Exception { 127 assertRoundTripEquals(message, TypeRegistry.getEmptyTypeRegistry()); 128 } 129 assertRoundTripEquals(Message message, TypeRegistry registry)130 private void assertRoundTripEquals(Message message, TypeRegistry registry) throws Exception { 131 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 132 JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry); 133 Message.Builder builder = message.newBuilderForType(); 134 parser.merge(printer.print(message), builder); 135 Message parsedMessage = builder.build(); 136 assertEquals(message.toString(), parsedMessage.toString()); 137 } 138 toJsonString(Message message)139 private String toJsonString(Message message) throws IOException { 140 return JsonFormat.printer().print(message); 141 } 142 mergeFromJson(String json, Message.Builder builder)143 private void mergeFromJson(String json, Message.Builder builder) throws IOException { 144 JsonFormat.parser().merge(json, builder); 145 } 146 testAllFields()147 public void testAllFields() throws Exception { 148 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 149 setAllFields(builder); 150 TestAllTypes message = builder.build(); 151 152 assertEquals( 153 "{\n" 154 + " \"optionalInt32\": 1234,\n" 155 + " \"optionalInt64\": \"1234567890123456789\",\n" 156 + " \"optionalUint32\": 5678,\n" 157 + " \"optionalUint64\": \"2345678901234567890\",\n" 158 + " \"optionalSint32\": 9012,\n" 159 + " \"optionalSint64\": \"3456789012345678901\",\n" 160 + " \"optionalFixed32\": 3456,\n" 161 + " \"optionalFixed64\": \"4567890123456789012\",\n" 162 + " \"optionalSfixed32\": 7890,\n" 163 + " \"optionalSfixed64\": \"5678901234567890123\",\n" 164 + " \"optionalFloat\": 1.5,\n" 165 + " \"optionalDouble\": 1.25,\n" 166 + " \"optionalBool\": true,\n" 167 + " \"optionalString\": \"Hello world!\",\n" 168 + " \"optionalBytes\": \"AAEC\",\n" 169 + " \"optionalNestedMessage\": {\n" 170 + " \"value\": 100\n" 171 + " },\n" 172 + " \"optionalNestedEnum\": \"BAR\",\n" 173 + " \"repeatedInt32\": [1234, 234],\n" 174 + " \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n" 175 + " \"repeatedUint32\": [5678, 678],\n" 176 + " \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n" 177 + " \"repeatedSint32\": [9012, 10],\n" 178 + " \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n" 179 + " \"repeatedFixed32\": [3456, 456],\n" 180 + " \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n" 181 + " \"repeatedSfixed32\": [7890, 890],\n" 182 + " \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n" 183 + " \"repeatedFloat\": [1.5, 11.5],\n" 184 + " \"repeatedDouble\": [1.25, 11.25],\n" 185 + " \"repeatedBool\": [true, true],\n" 186 + " \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n" 187 + " \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n" 188 + " \"repeatedNestedMessage\": [{\n" 189 + " \"value\": 100\n" 190 + " }, {\n" 191 + " \"value\": 200\n" 192 + " }],\n" 193 + " \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n" 194 + "}", 195 toJsonString(message)); 196 197 assertRoundTripEquals(message); 198 } 199 testUnknownEnumValues()200 public void testUnknownEnumValues() throws Exception { 201 TestAllTypes message = TestAllTypes.newBuilder() 202 .setOptionalNestedEnumValue(12345) 203 .addRepeatedNestedEnumValue(12345) 204 .addRepeatedNestedEnumValue(0) 205 .build(); 206 assertEquals( 207 "{\n" 208 + " \"optionalNestedEnum\": 12345,\n" 209 + " \"repeatedNestedEnum\": [12345, \"FOO\"]\n" 210 + "}", toJsonString(message)); 211 assertRoundTripEquals(message); 212 213 TestMap.Builder mapBuilder = TestMap.newBuilder(); 214 mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0); 215 mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345); 216 TestMap mapMessage = mapBuilder.build(); 217 assertEquals( 218 "{\n" 219 + " \"int32ToEnumMap\": {\n" 220 + " \"1\": \"FOO\",\n" 221 + " \"2\": 12345\n" 222 + " }\n" 223 + "}", 224 toJsonString(mapMessage)); 225 assertRoundTripEquals(mapMessage); 226 } 227 testSpecialFloatValues()228 public void testSpecialFloatValues() throws Exception { 229 TestAllTypes message = TestAllTypes.newBuilder() 230 .addRepeatedFloat(Float.NaN) 231 .addRepeatedFloat(Float.POSITIVE_INFINITY) 232 .addRepeatedFloat(Float.NEGATIVE_INFINITY) 233 .addRepeatedDouble(Double.NaN) 234 .addRepeatedDouble(Double.POSITIVE_INFINITY) 235 .addRepeatedDouble(Double.NEGATIVE_INFINITY) 236 .build(); 237 assertEquals( 238 "{\n" 239 + " \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n" 240 + " \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n" 241 + "}", toJsonString(message)); 242 243 assertRoundTripEquals(message); 244 } 245 testParserAcceptStringForNumbericField()246 public void testParserAcceptStringForNumbericField() throws Exception { 247 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 248 mergeFromJson( 249 "{\n" 250 + " \"optionalInt32\": \"1234\",\n" 251 + " \"optionalUint32\": \"5678\",\n" 252 + " \"optionalSint32\": \"9012\",\n" 253 + " \"optionalFixed32\": \"3456\",\n" 254 + " \"optionalSfixed32\": \"7890\",\n" 255 + " \"optionalFloat\": \"1.5\",\n" 256 + " \"optionalDouble\": \"1.25\",\n" 257 + " \"optionalBool\": \"true\"\n" 258 + "}", builder); 259 TestAllTypes message = builder.build(); 260 assertEquals(1234, message.getOptionalInt32()); 261 assertEquals(5678, message.getOptionalUint32()); 262 assertEquals(9012, message.getOptionalSint32()); 263 assertEquals(3456, message.getOptionalFixed32()); 264 assertEquals(7890, message.getOptionalSfixed32()); 265 assertEquals(1.5f, message.getOptionalFloat()); 266 assertEquals(1.25, message.getOptionalDouble()); 267 assertEquals(true, message.getOptionalBool()); 268 } 269 testParserAcceptFloatingPointValueForIntegerField()270 public void testParserAcceptFloatingPointValueForIntegerField() throws Exception { 271 // Test that numeric values like "1.000", "1e5" will also be accepted. 272 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 273 mergeFromJson( 274 "{\n" 275 + " \"repeatedInt32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n" 276 + " \"repeatedUint32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n" 277 + " \"repeatedInt64\": [1.000, 1e5, \"1.000\", \"1e5\"],\n" 278 + " \"repeatedUint64\": [1.000, 1e5, \"1.000\", \"1e5\"]\n" 279 + "}", builder); 280 int[] expectedValues = new int[]{1, 100000, 1, 100000}; 281 assertEquals(4, builder.getRepeatedInt32Count()); 282 assertEquals(4, builder.getRepeatedUint32Count()); 283 assertEquals(4, builder.getRepeatedInt64Count()); 284 assertEquals(4, builder.getRepeatedUint64Count()); 285 for (int i = 0; i < 4; ++i) { 286 assertEquals(expectedValues[i], builder.getRepeatedInt32(i)); 287 assertEquals(expectedValues[i], builder.getRepeatedUint32(i)); 288 assertEquals(expectedValues[i], builder.getRepeatedInt64(i)); 289 assertEquals(expectedValues[i], builder.getRepeatedUint64(i)); 290 } 291 292 // Non-integers will still be rejected. 293 assertRejects("optionalInt32", "1.5"); 294 assertRejects("optionalUint32", "1.5"); 295 assertRejects("optionalInt64", "1.5"); 296 assertRejects("optionalUint64", "1.5"); 297 } 298 assertRejects(String name, String value)299 private void assertRejects(String name, String value) { 300 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 301 try { 302 // Numeric form is rejected. 303 mergeFromJson("{\"" + name + "\":" + value + "}", builder); 304 fail("Exception is expected."); 305 } catch (IOException e) { 306 // Expected. 307 } 308 try { 309 // String form is also rejected. 310 mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder); 311 fail("Exception is expected."); 312 } catch (IOException e) { 313 // Expected. 314 } 315 } 316 assertAccepts(String name, String value)317 private void assertAccepts(String name, String value) throws IOException { 318 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 319 // Both numeric form and string form are accepted. 320 mergeFromJson("{\"" + name + "\":" + value + "}", builder); 321 builder.clear(); 322 mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder); 323 } 324 testParserRejectOutOfRangeNumericValues()325 public void testParserRejectOutOfRangeNumericValues() throws Exception { 326 assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE)); 327 assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE)); 328 assertRejects("optionalInt32", String.valueOf(Integer.MAX_VALUE + 1L)); 329 assertRejects("optionalInt32", String.valueOf(Integer.MIN_VALUE - 1L)); 330 331 assertAccepts("optionalUint32", String.valueOf(Integer.MAX_VALUE + 1L)); 332 assertRejects("optionalUint32", "123456789012345"); 333 assertRejects("optionalUint32", "-1"); 334 335 BigInteger one = new BigInteger("1"); 336 BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE)); 337 BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE)); 338 assertAccepts("optionalInt64", maxLong.toString()); 339 assertAccepts("optionalInt64", minLong.toString()); 340 assertRejects("optionalInt64", maxLong.add(one).toString()); 341 assertRejects("optionalInt64", minLong.subtract(one).toString()); 342 343 assertAccepts("optionalUint64", maxLong.add(one).toString()); 344 assertRejects("optionalUint64", "1234567890123456789012345"); 345 assertRejects("optionalUint64", "-1"); 346 347 assertAccepts("optionalBool", "true"); 348 assertRejects("optionalBool", "1"); 349 assertRejects("optionalBool", "0"); 350 351 assertAccepts("optionalFloat", String.valueOf(Float.MAX_VALUE)); 352 assertAccepts("optionalFloat", String.valueOf(-Float.MAX_VALUE)); 353 assertRejects("optionalFloat", String.valueOf(Double.MAX_VALUE)); 354 assertRejects("optionalFloat", String.valueOf(-Double.MAX_VALUE)); 355 356 BigDecimal moreThanOne = new BigDecimal("1.000001"); 357 BigDecimal maxDouble = new BigDecimal(Double.MAX_VALUE); 358 BigDecimal minDouble = new BigDecimal(-Double.MAX_VALUE); 359 assertAccepts("optionalDouble", maxDouble.toString()); 360 assertAccepts("optionalDouble", minDouble.toString()); 361 assertRejects("optionalDouble", maxDouble.multiply(moreThanOne).toString()); 362 assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString()); 363 } 364 testParserAcceptNull()365 public void testParserAcceptNull() throws Exception { 366 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 367 mergeFromJson( 368 "{\n" 369 + " \"optionalInt32\": null,\n" 370 + " \"optionalInt64\": null,\n" 371 + " \"optionalUint32\": null,\n" 372 + " \"optionalUint64\": null,\n" 373 + " \"optionalSint32\": null,\n" 374 + " \"optionalSint64\": null,\n" 375 + " \"optionalFixed32\": null,\n" 376 + " \"optionalFixed64\": null,\n" 377 + " \"optionalSfixed32\": null,\n" 378 + " \"optionalSfixed64\": null,\n" 379 + " \"optionalFloat\": null,\n" 380 + " \"optionalDouble\": null,\n" 381 + " \"optionalBool\": null,\n" 382 + " \"optionalString\": null,\n" 383 + " \"optionalBytes\": null,\n" 384 + " \"optionalNestedMessage\": null,\n" 385 + " \"optionalNestedEnum\": null,\n" 386 + " \"repeatedInt32\": null,\n" 387 + " \"repeatedInt64\": null,\n" 388 + " \"repeatedUint32\": null,\n" 389 + " \"repeatedUint64\": null,\n" 390 + " \"repeatedSint32\": null,\n" 391 + " \"repeatedSint64\": null,\n" 392 + " \"repeatedFixed32\": null,\n" 393 + " \"repeatedFixed64\": null,\n" 394 + " \"repeatedSfixed32\": null,\n" 395 + " \"repeatedSfixed64\": null,\n" 396 + " \"repeatedFloat\": null,\n" 397 + " \"repeatedDouble\": null,\n" 398 + " \"repeatedBool\": null,\n" 399 + " \"repeatedString\": null,\n" 400 + " \"repeatedBytes\": null,\n" 401 + " \"repeatedNestedMessage\": null,\n" 402 + " \"repeatedNestedEnum\": null\n" 403 + "}", builder); 404 TestAllTypes message = builder.build(); 405 assertEquals(TestAllTypes.getDefaultInstance(), message); 406 407 // Repeated field elements cannot be null. 408 try { 409 builder = TestAllTypes.newBuilder(); 410 mergeFromJson( 411 "{\n" 412 + " \"repeatedInt32\": [null, null],\n" 413 + "}", builder); 414 fail(); 415 } catch (InvalidProtocolBufferException e) { 416 // Exception expected. 417 } 418 419 try { 420 builder = TestAllTypes.newBuilder(); 421 mergeFromJson( 422 "{\n" 423 + " \"repeatedNestedMessage\": [null, null],\n" 424 + "}", builder); 425 fail(); 426 } catch (InvalidProtocolBufferException e) { 427 // Exception expected. 428 } 429 } 430 testParserRejectDuplicatedFields()431 public void testParserRejectDuplicatedFields() throws Exception { 432 // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last 433 // one if multiple entries have the same name. This is not the desired behavior but it can 434 // only be fixed by using our own parser. Here we only test the cases where the names are 435 // different but still referring to the same field. 436 437 // Duplicated optional fields. 438 try { 439 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 440 mergeFromJson( 441 "{\n" 442 + " \"optionalNestedMessage\": {},\n" 443 + " \"optional_nested_message\": {}\n" 444 + "}", builder); 445 fail(); 446 } catch (InvalidProtocolBufferException e) { 447 // Exception expected. 448 } 449 450 // Duplicated repeated fields. 451 try { 452 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 453 mergeFromJson( 454 "{\n" 455 + " \"repeatedNestedMessage\": [null, null],\n" 456 + " \"repeated_nested_message\": [null, null]\n" 457 + "}", builder); 458 fail(); 459 } catch (InvalidProtocolBufferException e) { 460 // Exception expected. 461 } 462 463 // Duplicated oneof fields. 464 try { 465 TestOneof.Builder builder = TestOneof.newBuilder(); 466 mergeFromJson( 467 "{\n" 468 + " \"oneofInt32\": 1,\n" 469 + " \"oneof_int32\": 2\n" 470 + "}", builder); 471 fail(); 472 } catch (InvalidProtocolBufferException e) { 473 // Exception expected. 474 } 475 } 476 testMapFields()477 public void testMapFields() throws Exception { 478 TestMap.Builder builder = TestMap.newBuilder(); 479 builder.getMutableInt32ToInt32Map().put(1, 10); 480 builder.getMutableInt64ToInt32Map().put(1234567890123456789L, 10); 481 builder.getMutableUint32ToInt32Map().put(2, 20); 482 builder.getMutableUint64ToInt32Map().put(2234567890123456789L, 20); 483 builder.getMutableSint32ToInt32Map().put(3, 30); 484 builder.getMutableSint64ToInt32Map().put(3234567890123456789L, 30); 485 builder.getMutableFixed32ToInt32Map().put(4, 40); 486 builder.getMutableFixed64ToInt32Map().put(4234567890123456789L, 40); 487 builder.getMutableSfixed32ToInt32Map().put(5, 50); 488 builder.getMutableSfixed64ToInt32Map().put(5234567890123456789L, 50); 489 builder.getMutableBoolToInt32Map().put(false, 6); 490 builder.getMutableStringToInt32Map().put("Hello", 10); 491 492 builder.getMutableInt32ToInt64Map().put(1, 1234567890123456789L); 493 builder.getMutableInt32ToUint32Map().put(2, 20); 494 builder.getMutableInt32ToUint64Map().put(2, 2234567890123456789L); 495 builder.getMutableInt32ToSint32Map().put(3, 30); 496 builder.getMutableInt32ToSint64Map().put(3, 3234567890123456789L); 497 builder.getMutableInt32ToFixed32Map().put(4, 40); 498 builder.getMutableInt32ToFixed64Map().put(4, 4234567890123456789L); 499 builder.getMutableInt32ToSfixed32Map().put(5, 50); 500 builder.getMutableInt32ToSfixed64Map().put(5, 5234567890123456789L); 501 builder.getMutableInt32ToFloatMap().put(6, 1.5f); 502 builder.getMutableInt32ToDoubleMap().put(6, 1.25); 503 builder.getMutableInt32ToBoolMap().put(7, false); 504 builder.getMutableInt32ToStringMap().put(7, "World"); 505 builder.getMutableInt32ToBytesMap().put( 506 8, ByteString.copyFrom(new byte[]{1, 2, 3})); 507 builder.getMutableInt32ToMessageMap().put( 508 8, NestedMessage.newBuilder().setValue(1234).build()); 509 builder.getMutableInt32ToEnumMap().put(9, NestedEnum.BAR); 510 TestMap message = builder.build(); 511 512 assertEquals( 513 "{\n" 514 + " \"int32ToInt32Map\": {\n" 515 + " \"1\": 10\n" 516 + " },\n" 517 + " \"int64ToInt32Map\": {\n" 518 + " \"1234567890123456789\": 10\n" 519 + " },\n" 520 + " \"uint32ToInt32Map\": {\n" 521 + " \"2\": 20\n" 522 + " },\n" 523 + " \"uint64ToInt32Map\": {\n" 524 + " \"2234567890123456789\": 20\n" 525 + " },\n" 526 + " \"sint32ToInt32Map\": {\n" 527 + " \"3\": 30\n" 528 + " },\n" 529 + " \"sint64ToInt32Map\": {\n" 530 + " \"3234567890123456789\": 30\n" 531 + " },\n" 532 + " \"fixed32ToInt32Map\": {\n" 533 + " \"4\": 40\n" 534 + " },\n" 535 + " \"fixed64ToInt32Map\": {\n" 536 + " \"4234567890123456789\": 40\n" 537 + " },\n" 538 + " \"sfixed32ToInt32Map\": {\n" 539 + " \"5\": 50\n" 540 + " },\n" 541 + " \"sfixed64ToInt32Map\": {\n" 542 + " \"5234567890123456789\": 50\n" 543 + " },\n" 544 + " \"boolToInt32Map\": {\n" 545 + " \"false\": 6\n" 546 + " },\n" 547 + " \"stringToInt32Map\": {\n" 548 + " \"Hello\": 10\n" 549 + " },\n" 550 + " \"int32ToInt64Map\": {\n" 551 + " \"1\": \"1234567890123456789\"\n" 552 + " },\n" 553 + " \"int32ToUint32Map\": {\n" 554 + " \"2\": 20\n" 555 + " },\n" 556 + " \"int32ToUint64Map\": {\n" 557 + " \"2\": \"2234567890123456789\"\n" 558 + " },\n" 559 + " \"int32ToSint32Map\": {\n" 560 + " \"3\": 30\n" 561 + " },\n" 562 + " \"int32ToSint64Map\": {\n" 563 + " \"3\": \"3234567890123456789\"\n" 564 + " },\n" 565 + " \"int32ToFixed32Map\": {\n" 566 + " \"4\": 40\n" 567 + " },\n" 568 + " \"int32ToFixed64Map\": {\n" 569 + " \"4\": \"4234567890123456789\"\n" 570 + " },\n" 571 + " \"int32ToSfixed32Map\": {\n" 572 + " \"5\": 50\n" 573 + " },\n" 574 + " \"int32ToSfixed64Map\": {\n" 575 + " \"5\": \"5234567890123456789\"\n" 576 + " },\n" 577 + " \"int32ToFloatMap\": {\n" 578 + " \"6\": 1.5\n" 579 + " },\n" 580 + " \"int32ToDoubleMap\": {\n" 581 + " \"6\": 1.25\n" 582 + " },\n" 583 + " \"int32ToBoolMap\": {\n" 584 + " \"7\": false\n" 585 + " },\n" 586 + " \"int32ToStringMap\": {\n" 587 + " \"7\": \"World\"\n" 588 + " },\n" 589 + " \"int32ToBytesMap\": {\n" 590 + " \"8\": \"AQID\"\n" 591 + " },\n" 592 + " \"int32ToMessageMap\": {\n" 593 + " \"8\": {\n" 594 + " \"value\": 1234\n" 595 + " }\n" 596 + " },\n" 597 + " \"int32ToEnumMap\": {\n" 598 + " \"9\": \"BAR\"\n" 599 + " }\n" 600 + "}", toJsonString(message)); 601 assertRoundTripEquals(message); 602 603 // Test multiple entries. 604 builder = TestMap.newBuilder(); 605 builder.getMutableInt32ToInt32Map().put(1, 2); 606 builder.getMutableInt32ToInt32Map().put(3, 4); 607 message = builder.build(); 608 609 assertEquals( 610 "{\n" 611 + " \"int32ToInt32Map\": {\n" 612 + " \"1\": 2,\n" 613 + " \"3\": 4\n" 614 + " }\n" 615 + "}", toJsonString(message)); 616 assertRoundTripEquals(message); 617 } 618 testMapNullValueIsRejected()619 public void testMapNullValueIsRejected() throws Exception { 620 try { 621 TestMap.Builder builder = TestMap.newBuilder(); 622 mergeFromJson( 623 "{\n" 624 + " \"int32ToInt32Map\": {null: 1},\n" 625 + " \"int32ToMessageMap\": {null: 2}\n" 626 + "}", builder); 627 fail(); 628 } catch (InvalidProtocolBufferException e) { 629 // Exception expected. 630 } 631 632 try { 633 TestMap.Builder builder = TestMap.newBuilder(); 634 mergeFromJson( 635 "{\n" 636 + " \"int32ToInt32Map\": {\"1\": null},\n" 637 + " \"int32ToMessageMap\": {\"2\": null}\n" 638 + "}", builder); 639 fail(); 640 } catch (InvalidProtocolBufferException e) { 641 // Exception expected. 642 } 643 } 644 testParserAcceptNonQuotedObjectKey()645 public void testParserAcceptNonQuotedObjectKey() throws Exception { 646 TestMap.Builder builder = TestMap.newBuilder(); 647 mergeFromJson( 648 "{\n" 649 + " int32ToInt32Map: {1: 2},\n" 650 + " stringToInt32Map: {hello: 3}\n" 651 + "}", builder); 652 TestMap message = builder.build(); 653 assertEquals(2, message.getInt32ToInt32Map().get(1).intValue()); 654 assertEquals(3, message.getStringToInt32Map().get("hello").intValue()); 655 } 656 testWrappers()657 public void testWrappers() throws Exception { 658 TestWrappers.Builder builder = TestWrappers.newBuilder(); 659 builder.getBoolValueBuilder().setValue(false); 660 builder.getInt32ValueBuilder().setValue(0); 661 builder.getInt64ValueBuilder().setValue(0); 662 builder.getUint32ValueBuilder().setValue(0); 663 builder.getUint64ValueBuilder().setValue(0); 664 builder.getFloatValueBuilder().setValue(0.0f); 665 builder.getDoubleValueBuilder().setValue(0.0); 666 builder.getStringValueBuilder().setValue(""); 667 builder.getBytesValueBuilder().setValue(ByteString.EMPTY); 668 TestWrappers message = builder.build(); 669 670 assertEquals( 671 "{\n" 672 + " \"int32Value\": 0,\n" 673 + " \"uint32Value\": 0,\n" 674 + " \"int64Value\": \"0\",\n" 675 + " \"uint64Value\": \"0\",\n" 676 + " \"floatValue\": 0.0,\n" 677 + " \"doubleValue\": 0.0,\n" 678 + " \"boolValue\": false,\n" 679 + " \"stringValue\": \"\",\n" 680 + " \"bytesValue\": \"\"\n" 681 + "}", toJsonString(message)); 682 assertRoundTripEquals(message); 683 684 builder = TestWrappers.newBuilder(); 685 builder.getBoolValueBuilder().setValue(true); 686 builder.getInt32ValueBuilder().setValue(1); 687 builder.getInt64ValueBuilder().setValue(2); 688 builder.getUint32ValueBuilder().setValue(3); 689 builder.getUint64ValueBuilder().setValue(4); 690 builder.getFloatValueBuilder().setValue(5.0f); 691 builder.getDoubleValueBuilder().setValue(6.0); 692 builder.getStringValueBuilder().setValue("7"); 693 builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[]{8})); 694 message = builder.build(); 695 696 assertEquals( 697 "{\n" 698 + " \"int32Value\": 1,\n" 699 + " \"uint32Value\": 3,\n" 700 + " \"int64Value\": \"2\",\n" 701 + " \"uint64Value\": \"4\",\n" 702 + " \"floatValue\": 5.0,\n" 703 + " \"doubleValue\": 6.0,\n" 704 + " \"boolValue\": true,\n" 705 + " \"stringValue\": \"7\",\n" 706 + " \"bytesValue\": \"CA==\"\n" 707 + "}", toJsonString(message)); 708 assertRoundTripEquals(message); 709 } 710 testTimestamp()711 public void testTimestamp() throws Exception { 712 TestTimestamp message = TestTimestamp.newBuilder() 713 .setTimestampValue(TimeUtil.parseTimestamp("1970-01-01T00:00:00Z")) 714 .build(); 715 716 assertEquals( 717 "{\n" 718 + " \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" 719 + "}", toJsonString(message)); 720 assertRoundTripEquals(message); 721 } 722 testDuration()723 public void testDuration() throws Exception { 724 TestDuration message = TestDuration.newBuilder() 725 .setDurationValue(TimeUtil.parseDuration("12345s")) 726 .build(); 727 728 assertEquals( 729 "{\n" 730 + " \"durationValue\": \"12345s\"\n" 731 + "}", toJsonString(message)); 732 assertRoundTripEquals(message); 733 } 734 testFieldMask()735 public void testFieldMask() throws Exception { 736 TestFieldMask message = TestFieldMask.newBuilder() 737 .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz")) 738 .build(); 739 740 assertEquals( 741 "{\n" 742 + " \"fieldMaskValue\": \"foo.bar,baz\"\n" 743 + "}", toJsonString(message)); 744 assertRoundTripEquals(message); 745 } 746 testStruct()747 public void testStruct() throws Exception { 748 // Build a struct with all possible values. 749 TestStruct.Builder builder = TestStruct.newBuilder(); 750 Struct.Builder structBuilder = builder.getStructValueBuilder(); 751 structBuilder.getMutableFields().put( 752 "null_value", Value.newBuilder().setNullValueValue(0).build()); 753 structBuilder.getMutableFields().put( 754 "number_value", Value.newBuilder().setNumberValue(1.25).build()); 755 structBuilder.getMutableFields().put( 756 "string_value", Value.newBuilder().setStringValue("hello").build()); 757 Struct.Builder subStructBuilder = Struct.newBuilder(); 758 subStructBuilder.getMutableFields().put( 759 "number_value", Value.newBuilder().setNumberValue(1234).build()); 760 structBuilder.getMutableFields().put( 761 "struct_value", Value.newBuilder().setStructValue(subStructBuilder.build()).build()); 762 ListValue.Builder listBuilder = ListValue.newBuilder(); 763 listBuilder.addValues(Value.newBuilder().setNumberValue(1.125).build()); 764 listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build()); 765 structBuilder.getMutableFields().put( 766 "list_value", Value.newBuilder().setListValue(listBuilder.build()).build()); 767 TestStruct message = builder.build(); 768 769 assertEquals( 770 "{\n" 771 + " \"structValue\": {\n" 772 + " \"null_value\": null,\n" 773 + " \"number_value\": 1.25,\n" 774 + " \"string_value\": \"hello\",\n" 775 + " \"struct_value\": {\n" 776 + " \"number_value\": 1234.0\n" 777 + " },\n" 778 + " \"list_value\": [1.125, null]\n" 779 + " }\n" 780 + "}", toJsonString(message)); 781 assertRoundTripEquals(message); 782 783 builder = TestStruct.newBuilder(); 784 builder.setValue(Value.newBuilder().setNullValueValue(0).build()); 785 message = builder.build(); 786 assertEquals( 787 "{\n" 788 + " \"value\": null\n" 789 + "}", toJsonString(message)); 790 assertRoundTripEquals(message); 791 792 builder = TestStruct.newBuilder(); 793 listBuilder = builder.getListValueBuilder(); 794 listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build()); 795 listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build()); 796 message = builder.build(); 797 assertEquals( 798 "{\n" 799 + " \"listValue\": [31831.125, null]\n" 800 + "}", toJsonString(message)); 801 assertRoundTripEquals(message); 802 } 803 testAnyFields()804 public void testAnyFields() throws Exception { 805 TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build(); 806 TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build(); 807 808 // A TypeRegistry must be provided in order to convert Any types. 809 try { 810 toJsonString(message); 811 fail("Exception is expected."); 812 } catch (IOException e) { 813 // Expected. 814 } 815 816 JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder() 817 .add(TestAllTypes.getDescriptor()).build(); 818 JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); 819 820 assertEquals( 821 "{\n" 822 + " \"anyValue\": {\n" 823 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 824 + " \"optionalInt32\": 1234\n" 825 + " }\n" 826 + "}" , printer.print(message)); 827 assertRoundTripEquals(message, registry); 828 829 830 // Well-known types have a special formatting when embedded in Any. 831 // 832 // 1. Any in Any. 833 Any anyMessage = Any.pack(Any.pack(content)); 834 assertEquals( 835 "{\n" 836 + " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n" 837 + " \"value\": {\n" 838 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 839 + " \"optionalInt32\": 1234\n" 840 + " }\n" 841 + "}", printer.print(anyMessage)); 842 assertRoundTripEquals(anyMessage, registry); 843 844 // 2. Wrappers in Any. 845 anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build()); 846 assertEquals( 847 "{\n" 848 + " \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n" 849 + " \"value\": 12345\n" 850 + "}", printer.print(anyMessage)); 851 assertRoundTripEquals(anyMessage, registry); 852 anyMessage = Any.pack(UInt32Value.newBuilder().setValue(12345).build()); 853 assertEquals( 854 "{\n" 855 + " \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n" 856 + " \"value\": 12345\n" 857 + "}", printer.print(anyMessage)); 858 assertRoundTripEquals(anyMessage, registry); 859 anyMessage = Any.pack(Int64Value.newBuilder().setValue(12345).build()); 860 assertEquals( 861 "{\n" 862 + " \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n" 863 + " \"value\": \"12345\"\n" 864 + "}", printer.print(anyMessage)); 865 assertRoundTripEquals(anyMessage, registry); 866 anyMessage = Any.pack(UInt64Value.newBuilder().setValue(12345).build()); 867 assertEquals( 868 "{\n" 869 + " \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n" 870 + " \"value\": \"12345\"\n" 871 + "}", printer.print(anyMessage)); 872 assertRoundTripEquals(anyMessage, registry); 873 anyMessage = Any.pack(FloatValue.newBuilder().setValue(12345).build()); 874 assertEquals( 875 "{\n" 876 + " \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n" 877 + " \"value\": 12345.0\n" 878 + "}", printer.print(anyMessage)); 879 assertRoundTripEquals(anyMessage, registry); 880 anyMessage = Any.pack(DoubleValue.newBuilder().setValue(12345).build()); 881 assertEquals( 882 "{\n" 883 + " \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n" 884 + " \"value\": 12345.0\n" 885 + "}", printer.print(anyMessage)); 886 assertRoundTripEquals(anyMessage, registry); 887 anyMessage = Any.pack(BoolValue.newBuilder().setValue(true).build()); 888 assertEquals( 889 "{\n" 890 + " \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n" 891 + " \"value\": true\n" 892 + "}", printer.print(anyMessage)); 893 assertRoundTripEquals(anyMessage, registry); 894 anyMessage = Any.pack(StringValue.newBuilder().setValue("Hello").build()); 895 assertEquals( 896 "{\n" 897 + " \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n" 898 + " \"value\": \"Hello\"\n" 899 + "}", printer.print(anyMessage)); 900 assertRoundTripEquals(anyMessage, registry); 901 anyMessage = Any.pack(BytesValue.newBuilder().setValue( 902 ByteString.copyFrom(new byte[]{1, 2})).build()); 903 assertEquals( 904 "{\n" 905 + " \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n" 906 + " \"value\": \"AQI=\"\n" 907 + "}", printer.print(anyMessage)); 908 assertRoundTripEquals(anyMessage, registry); 909 910 // 3. Timestamp in Any. 911 anyMessage = Any.pack(TimeUtil.parseTimestamp("1969-12-31T23:59:59Z")); 912 assertEquals( 913 "{\n" 914 + " \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n" 915 + " \"value\": \"1969-12-31T23:59:59Z\"\n" 916 + "}", printer.print(anyMessage)); 917 assertRoundTripEquals(anyMessage, registry); 918 919 // 4. Duration in Any 920 anyMessage = Any.pack(TimeUtil.parseDuration("12345.10s")); 921 assertEquals( 922 "{\n" 923 + " \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n" 924 + " \"value\": \"12345.100s\"\n" 925 + "}", printer.print(anyMessage)); 926 assertRoundTripEquals(anyMessage, registry); 927 928 // 5. FieldMask in Any 929 anyMessage = Any.pack(FieldMaskUtil.fromString("foo.bar,baz")); 930 assertEquals( 931 "{\n" 932 + " \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n" 933 + " \"value\": \"foo.bar,baz\"\n" 934 + "}", printer.print(anyMessage)); 935 assertRoundTripEquals(anyMessage, registry); 936 937 // 6. Struct in Any 938 Struct.Builder structBuilder = Struct.newBuilder(); 939 structBuilder.getMutableFields().put( 940 "number", Value.newBuilder().setNumberValue(1.125).build()); 941 anyMessage = Any.pack(structBuilder.build()); 942 assertEquals( 943 "{\n" 944 + " \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n" 945 + " \"value\": {\n" 946 + " \"number\": 1.125\n" 947 + " }\n" 948 + "}", printer.print(anyMessage)); 949 assertRoundTripEquals(anyMessage, registry); 950 Value.Builder valueBuilder = Value.newBuilder(); 951 valueBuilder.setNumberValue(1); 952 anyMessage = Any.pack(valueBuilder.build()); 953 assertEquals( 954 "{\n" 955 + " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n" 956 + " \"value\": 1.0\n" 957 + "}", printer.print(anyMessage)); 958 assertRoundTripEquals(anyMessage, registry); 959 } 960 testParserMissingTypeUrl()961 public void testParserMissingTypeUrl() throws Exception { 962 try { 963 Any.Builder builder = Any.newBuilder(); 964 mergeFromJson( 965 "{\n" 966 + " \"optionalInt32\": 1234\n" 967 + "}", builder); 968 fail("Exception is expected."); 969 } catch (IOException e) { 970 // Expected. 971 } 972 } 973 testParserUnexpectedTypeUrl()974 public void testParserUnexpectedTypeUrl() throws Exception { 975 try { 976 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 977 mergeFromJson( 978 "{\n" 979 + " \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n" 980 + " \"optionalInt32\": 12345\n" 981 + "}", builder); 982 fail("Exception is expected."); 983 } catch (IOException e) { 984 // Expected. 985 } 986 } 987 testParserRejectTrailingComma()988 public void testParserRejectTrailingComma() throws Exception { 989 try { 990 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 991 mergeFromJson( 992 "{\n" 993 + " \"optionalInt32\": 12345,\n" 994 + "}", builder); 995 fail("Exception is expected."); 996 } catch (IOException e) { 997 // Expected. 998 } 999 1000 // TODO(xiaofeng): GSON allows trailing comma in arrays even after I set 1001 // the JsonReader to non-lenient mode. If we want to enforce strict JSON 1002 // compliance, we might want to switch to a different JSON parser or 1003 // implement one by ourselves. 1004 // try { 1005 // TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1006 // JsonFormat.merge( 1007 // "{\n" 1008 // + " \"repeatedInt32\": [12345,]\n" 1009 // + "}", builder); 1010 // fail("Exception is expected."); 1011 // } catch (IOException e) { 1012 // // Expected. 1013 // } 1014 } 1015 testParserRejectInvalidBase64()1016 public void testParserRejectInvalidBase64() throws Exception { 1017 assertRejects("optionalBytes", "!@#$"); 1018 // We use standard BASE64 with paddings. 1019 assertRejects("optionalBytes", "AQI"); 1020 } 1021 testParserRejectInvalidEnumValue()1022 public void testParserRejectInvalidEnumValue() throws Exception { 1023 try { 1024 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1025 mergeFromJson( 1026 "{\n" 1027 + " \"optionalNestedEnum\": \"XXX\"\n" 1028 + "}", builder); 1029 fail("Exception is expected."); 1030 } catch (InvalidProtocolBufferException e) { 1031 // Expected. 1032 } 1033 } 1034 testCustomJsonName()1035 public void testCustomJsonName() throws Exception { 1036 TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build(); 1037 assertEquals("{\n" + " \"@value\": 12345\n" + "}", JsonFormat.printer().print(message)); 1038 assertRoundTripEquals(message); 1039 } 1040 testDefaultGsonDoesNotHtmlEscape()1041 public void testDefaultGsonDoesNotHtmlEscape() throws Exception { 1042 TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build(); 1043 assertEquals( 1044 "{\n" + " \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message)); 1045 } 1046 testIncludingDefaultValueFields()1047 public void testIncludingDefaultValueFields() throws Exception { 1048 TestAllTypes message = TestAllTypes.getDefaultInstance(); 1049 assertEquals("{\n}", JsonFormat.printer().print(message)); 1050 assertEquals( 1051 "{\n" 1052 + " \"optionalInt32\": 0,\n" 1053 + " \"optionalInt64\": \"0\",\n" 1054 + " \"optionalUint32\": 0,\n" 1055 + " \"optionalUint64\": \"0\",\n" 1056 + " \"optionalSint32\": 0,\n" 1057 + " \"optionalSint64\": \"0\",\n" 1058 + " \"optionalFixed32\": 0,\n" 1059 + " \"optionalFixed64\": \"0\",\n" 1060 + " \"optionalSfixed32\": 0,\n" 1061 + " \"optionalSfixed64\": \"0\",\n" 1062 + " \"optionalFloat\": 0.0,\n" 1063 + " \"optionalDouble\": 0.0,\n" 1064 + " \"optionalBool\": false,\n" 1065 + " \"optionalString\": \"\",\n" 1066 + " \"optionalBytes\": \"\",\n" 1067 + " \"optionalNestedEnum\": \"FOO\",\n" 1068 + " \"repeatedInt32\": [],\n" 1069 + " \"repeatedInt64\": [],\n" 1070 + " \"repeatedUint32\": [],\n" 1071 + " \"repeatedUint64\": [],\n" 1072 + " \"repeatedSint32\": [],\n" 1073 + " \"repeatedSint64\": [],\n" 1074 + " \"repeatedFixed32\": [],\n" 1075 + " \"repeatedFixed64\": [],\n" 1076 + " \"repeatedSfixed32\": [],\n" 1077 + " \"repeatedSfixed64\": [],\n" 1078 + " \"repeatedFloat\": [],\n" 1079 + " \"repeatedDouble\": [],\n" 1080 + " \"repeatedBool\": [],\n" 1081 + " \"repeatedString\": [],\n" 1082 + " \"repeatedBytes\": [],\n" 1083 + " \"repeatedNestedMessage\": [],\n" 1084 + " \"repeatedNestedEnum\": []\n" 1085 + "}", 1086 JsonFormat.printer().includingDefaultValueFields().print(message)); 1087 1088 TestMap mapMessage = TestMap.getDefaultInstance(); 1089 assertEquals("{\n}", JsonFormat.printer().print(mapMessage)); 1090 assertEquals( 1091 "{\n" 1092 + " \"int32ToInt32Map\": {\n" 1093 + " },\n" 1094 + " \"int64ToInt32Map\": {\n" 1095 + " },\n" 1096 + " \"uint32ToInt32Map\": {\n" 1097 + " },\n" 1098 + " \"uint64ToInt32Map\": {\n" 1099 + " },\n" 1100 + " \"sint32ToInt32Map\": {\n" 1101 + " },\n" 1102 + " \"sint64ToInt32Map\": {\n" 1103 + " },\n" 1104 + " \"fixed32ToInt32Map\": {\n" 1105 + " },\n" 1106 + " \"fixed64ToInt32Map\": {\n" 1107 + " },\n" 1108 + " \"sfixed32ToInt32Map\": {\n" 1109 + " },\n" 1110 + " \"sfixed64ToInt32Map\": {\n" 1111 + " },\n" 1112 + " \"boolToInt32Map\": {\n" 1113 + " },\n" 1114 + " \"stringToInt32Map\": {\n" 1115 + " },\n" 1116 + " \"int32ToInt64Map\": {\n" 1117 + " },\n" 1118 + " \"int32ToUint32Map\": {\n" 1119 + " },\n" 1120 + " \"int32ToUint64Map\": {\n" 1121 + " },\n" 1122 + " \"int32ToSint32Map\": {\n" 1123 + " },\n" 1124 + " \"int32ToSint64Map\": {\n" 1125 + " },\n" 1126 + " \"int32ToFixed32Map\": {\n" 1127 + " },\n" 1128 + " \"int32ToFixed64Map\": {\n" 1129 + " },\n" 1130 + " \"int32ToSfixed32Map\": {\n" 1131 + " },\n" 1132 + " \"int32ToSfixed64Map\": {\n" 1133 + " },\n" 1134 + " \"int32ToFloatMap\": {\n" 1135 + " },\n" 1136 + " \"int32ToDoubleMap\": {\n" 1137 + " },\n" 1138 + " \"int32ToBoolMap\": {\n" 1139 + " },\n" 1140 + " \"int32ToStringMap\": {\n" 1141 + " },\n" 1142 + " \"int32ToBytesMap\": {\n" 1143 + " },\n" 1144 + " \"int32ToMessageMap\": {\n" 1145 + " },\n" 1146 + " \"int32ToEnumMap\": {\n" 1147 + " }\n" 1148 + "}", 1149 JsonFormat.printer().includingDefaultValueFields().print(mapMessage)); 1150 } 1151 testPreservingProtoFieldNames()1152 public void testPreservingProtoFieldNames() throws Exception { 1153 TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build(); 1154 assertEquals("{\n" + " \"optionalInt32\": 12345\n" + "}", JsonFormat.printer().print(message)); 1155 assertEquals( 1156 "{\n" + " \"optional_int32\": 12345\n" + "}", 1157 JsonFormat.printer().preservingProtoFieldNames().print(message)); 1158 1159 // The json_name field option is ignored when configured to use original proto field names. 1160 TestCustomJsonName messageWithCustomJsonName = 1161 TestCustomJsonName.newBuilder().setValue(12345).build(); 1162 assertEquals( 1163 "{\n" + " \"value\": 12345\n" + "}", 1164 JsonFormat.printer().preservingProtoFieldNames().print(messageWithCustomJsonName)); 1165 1166 // Parsers accept both original proto field names and lowerCamelCase names. 1167 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1168 JsonFormat.parser().merge("{\"optionalInt32\": 12345}", builder); 1169 assertEquals(12345, builder.getOptionalInt32()); 1170 builder.clear(); 1171 JsonFormat.parser().merge("{\"optional_int32\": 54321}", builder); 1172 assertEquals(54321, builder.getOptionalInt32()); 1173 } 1174 } 1175