From e83bbbbe4213e9b7bcc0529c305b821da8d7a136 Mon Sep 17 00:00:00 2001 From: Ulas Kirazci Date: Mon, 1 Apr 2013 11:29:43 -0700 Subject: Add an option to inspect "has" state upon parse. If has is set, also always serialize. Change-Id: I2c8450f7ab9e837d722123dd1042991c0258ede3 --- java/README.txt | 16 ++++ .../test/java/com/google/protobuf/NanoTest.java | 88 ++++++++++++++++++++++ 2 files changed, 104 insertions(+) (limited to 'java') diff --git a/java/README.txt b/java/README.txt index dac2e3c9..58ccb88e 100644 --- a/java/README.txt +++ b/java/README.txt @@ -301,6 +301,22 @@ message's constructor or clear() function is called, the default value penalty. This is not a problem if the field has no default or is an empty default. +Nano Generator options + +java_nano_generate_has: + If true, generates a public boolean variable has + accompanying the optional or required field (not present for + repeated fields, groups or messages). It is set to false initially + and upon clear(). If parseFrom(...) reads the field from the wire, + it is set to true. This is a way for clients to inspect the "has" + value upon parse. If it is set to true, writeTo(...) will ALWAYS + output that field (even if field value is equal to its + default). + + IMPORTANT: This option costs an extra 4 bytes per primitive field in + the message. Think carefully about whether you really need this. In + many cases reading the default works and determining whether the + field was received over the wire is irrelevant. To use nano protobufs: diff --git a/java/src/test/java/com/google/protobuf/NanoTest.java b/java/src/test/java/com/google/protobuf/NanoTest.java index 0ea80d40..80f091bf 100644 --- a/java/src/test/java/com/google/protobuf/NanoTest.java +++ b/java/src/test/java/com/google/protobuf/NanoTest.java @@ -37,6 +37,7 @@ import com.google.protobuf.nano.InternalNano; import com.google.protobuf.nano.MessageNano; import com.google.protobuf.nano.MultipleImportingNonMultipleNano1; import com.google.protobuf.nano.MultipleImportingNonMultipleNano2; +import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas; import com.google.protobuf.nano.NanoOuterClass; import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano; import com.google.protobuf.nano.RecursiveMessageNano; @@ -2095,6 +2096,93 @@ public class NanoTest extends TestCase { } } + public void testNanoWithHasParseFrom() throws Exception { + TestAllTypesNanoHas msg = null; + // Test false on creation, after clear and upon empty parse. + for (int i = 0; i < 3; i++) { + if (i == 0) { + msg = new TestAllTypesNanoHas(); + } else if (i == 1) { + msg.clear(); + } else if (i == 2) { + msg = TestAllTypesNanoHas.parseFrom(new byte[0]); + } + assertFalse(msg.hasOptionalInt32); + assertFalse(msg.hasOptionalString); + assertFalse(msg.hasOptionalBytes); + assertFalse(msg.hasOptionalNestedEnum); + assertFalse(msg.hasDefaultInt32); + assertFalse(msg.hasDefaultString); + assertFalse(msg.hasDefaultBytes); + assertFalse(msg.hasDefaultFloatNan); + assertFalse(msg.hasDefaultNestedEnum); + assertFalse(msg.hasId); + msg.optionalInt32 = 123; + msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage(); + msg.optionalNestedMessage.bb = 2; + msg.optionalNestedEnum = TestAllTypesNano.BAZ; + } + + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 13); + assertEquals(result.length, msgSerializedSize); + + // Has fields true upon parse. + TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result); + assertEquals(123, newMsg.optionalInt32); + assertTrue(newMsg.hasOptionalInt32); + assertEquals(2, newMsg.optionalNestedMessage.bb); + assertTrue(newMsg.optionalNestedMessage.hasBb); + assertEquals(TestAllTypesNanoHas.BAZ, newMsg.optionalNestedEnum); + assertTrue(newMsg.hasOptionalNestedEnum); + } + + public void testNanoWithHasSerialize() throws Exception { + TestAllTypesNanoHas msg = new TestAllTypesNanoHas(); + msg.hasOptionalInt32 = true; + msg.hasOptionalString = true; + msg.hasOptionalBytes = true; + msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage(); + msg.optionalNestedMessage.hasBb = true; + msg.hasOptionalNestedEnum = true; + msg.hasDefaultInt32 = true; + msg.hasDefaultString = true; + msg.hasDefaultBytes = true; + msg.hasDefaultFloatNan = true; + msg.hasDefaultNestedEnum = true; + + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + assertEquals(result.length, msgSerializedSize); + + // Now deserialize and find that all fields are set and equal to their defaults. + TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result); + assertTrue(newMsg.hasOptionalInt32); + assertTrue(newMsg.hasOptionalString); + assertTrue(newMsg.hasOptionalBytes); + assertTrue(newMsg.optionalNestedMessage.hasBb); + assertTrue(newMsg.hasOptionalNestedEnum); + assertTrue(newMsg.hasDefaultInt32); + assertTrue(newMsg.hasDefaultString); + assertTrue(newMsg.hasDefaultBytes); + assertTrue(newMsg.hasDefaultFloatNan); + assertTrue(newMsg.hasDefaultNestedEnum); + assertTrue(newMsg.hasId); + assertEquals(0, newMsg.optionalInt32); + assertEquals(0, newMsg.optionalString.length()); + assertEquals(0, newMsg.optionalBytes.length); + assertEquals(0, newMsg.optionalNestedMessage.bb); + assertEquals(TestAllTypesNanoHas.FOO, newMsg.optionalNestedEnum); + assertEquals(41, newMsg.defaultInt32); + assertEquals("hello", newMsg.defaultString); + assertEquals("world", new String(newMsg.defaultBytes, "UTF-8")); + assertEquals(TestAllTypesNanoHas.BAR, newMsg.defaultNestedEnum); + assertEquals(Float.NaN, newMsg.defaultFloatNan); + assertEquals(0, newMsg.id); + } + /** * Tests that fields with a default value of NaN are not serialized when * set to NaN. This is a special case as NaN != NaN, so normal equality -- cgit v1.2.3