Jelajahi Sumber

Merge remote-tracking branch 'goog/klp-dev-plus-aosp' into tomerge

Max Cai 12 tahun lalu
induk
melakukan
39b3008709
23 mengubah file dengan 1371 tambahan dan 103 penghapusan
  1. 133 10
      java/README.txt
  2. 7 2
      java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
  3. 241 1
      java/src/test/java/com/google/protobuf/NanoTest.java
  4. 28 13
      src/google/protobuf/compiler/javanano/javanano_enum.cc
  5. 96 6
      src/google/protobuf/compiler/javanano/javanano_enum_field.cc
  6. 26 2
      src/google/protobuf/compiler/javanano/javanano_enum_field.h
  7. 23 3
      src/google/protobuf/compiler/javanano/javanano_field.cc
  8. 6 2
      src/google/protobuf/compiler/javanano/javanano_field.h
  9. 15 0
      src/google/protobuf/compiler/javanano/javanano_file.cc
  10. 18 1
      src/google/protobuf/compiler/javanano/javanano_generator.cc
  11. 110 6
      src/google/protobuf/compiler/javanano/javanano_helpers.cc
  12. 30 0
      src/google/protobuf/compiler/javanano/javanano_helpers.h
  13. 18 27
      src/google/protobuf/compiler/javanano/javanano_message.cc
  14. 92 3
      src/google/protobuf/compiler/javanano/javanano_message_field.cc
  15. 26 2
      src/google/protobuf/compiler/javanano/javanano_message_field.h
  16. 27 1
      src/google/protobuf/compiler/javanano/javanano_params.h
  17. 115 22
      src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
  18. 26 2
      src/google/protobuf/compiler/javanano/javanano_primitive_field.h
  19. 116 0
      src/google/protobuf/unittest_accessors_nano.proto
  20. 48 0
      src/google/protobuf/unittest_enum_class_multiple_nano.proto
  21. 48 0
      src/google/protobuf/unittest_enum_class_nano.proto
  22. 6 0
      src/google/protobuf/unittest_extension_nano.proto
  23. 116 0
      src/google/protobuf/unittest_reference_types_nano.proto

+ 133 - 10
java/README.txt

@@ -93,8 +93,9 @@ Micro version
 The runtime and generated code for MICRO_RUNTIME is smaller
 because it does not include support for the descriptor and
 reflection, and enums are generated as integer constants in
-the parent message or the file's outer class. Also, not
-currently supported are packed repeated elements or
+the parent message or the file's outer class, with no
+protection against invalid values set to enum fields. Also,
+not currently supported are packed repeated elements or
 extensions.
 
 To create a jar file for the runtime and run tests invoke
@@ -409,11 +410,20 @@ Nano version
 ============================
 
 Nano is even smaller than micro, especially in the number of generated
-functions. It is like micro except:
+functions. It is like micro:
 
-- No setter/getter/hazzer functions.
-- Has state is not available. Outputs all fields not equal to their
-  default. (See important implications below.)
+- No support for descriptors and reflection;
+- Enum constants are integers with no protection against invalid
+  values set to enum fields.
+
+Except:
+
+- Setter/getter/hazzer/clearer functions are opt-in.
+- If not opted in, has state is not available. Serialization outputs
+  all fields not equal to their default. (See important implications
+  below.)
+- Enum constants can be generated into container interfaces bearing
+  the enum's name (so the referencing code is in Java style).
 - CodedInputStreamMicro is renamed to CodedInputByteBufferNano and can
   only take byte[] (not InputStream).
 - Similar rename from CodedOutputStreamMicro to
@@ -426,7 +436,7 @@ functions. It is like micro except:
   MessageNano.
 - "bytes" are of java type byte[].
 
-IMPORTANT: If you have fields with defaults
+IMPORTANT: If you have fields with defaults and opt out of accessors
 
 How fields with defaults are serialized has changed. Because we don't
 keep "has" state, any field equal to its default is assumed to be not
@@ -435,7 +445,8 @@ change the default value of a field. Senders compiled against an older
 version of the proto continue to match against the old default, and
 don't send values to the receiver even though the receiver assumes the
 new default value. Therefore, think carefully about the implications
-of changing the default value.
+of changing the default value. Alternatively, turn on accessors and
+enjoy the benefit of the explicit has() checks.
 
 IMPORTANT: If you have "bytes" fields with non-empty defaults
 
@@ -451,7 +462,9 @@ Nano Generator options
 java_package           -> <file-name>|<package-name>
 java_outer_classname   -> <file-name>|<package-name>
 java_multiple_files    -> true or false
-java_nano_generate_has -> true or false
+java_nano_generate_has -> true or false [DEPRECATED]
+optional_field_style   -> default or accessors
+enum_style             -> c or java
 
 java_package:
 java_outer_classname:
@@ -459,6 +472,8 @@ java_multiple_files:
   Same as Micro version.
 
 java_nano_generate_has={true,false} (default: false)
+  DEPRECATED. Use optional_field_style=accessors.
+
   If true, generates a public boolean variable has<fieldname>
   accompanying each optional or required field (not present for
   repeated fields, groups or messages). It is set to false initially
@@ -473,7 +488,114 @@ java_nano_generate_has={true,false} (default: false)
   many cases reading the default works and determining whether the
   field was received over the wire is irrelevant.
 
-To use nano protobufs:
+optional_field_style={default,accessors,reftypes} (default: default)
+  Defines the style of the generated code for fields.
+
+  * default *
+
+  In the default style, optional fields translate into public mutable
+  Java fields, and the serialization process is as discussed in the
+  "IMPORTANT" section above. 
+
+  * accessors *
+
+  When set to 'accessors', each optional field is encapsulated behind
+  4 accessors, namely get<fieldname>(), set<fieldname>(), has<fieldname>()
+  and clear<fieldname>() methods, with the standard semantics. The hazzer's
+  return value determines whether a field is serialized, so this style is
+  useful when you need to serialize a field with the default value, or check
+  if a field has been explicitly set to its default value from the wire.
+
+  In the 'accessors' style, required fields are still translated to one
+  public mutable Java field each, and repeated fields are still translated
+  to arrays. No accessors are generated for them.
+
+  IMPORTANT: When using the 'accessors' style, ProGuard should always
+  be enabled with optimization (don't use -dontoptimize) and allowing
+  access modification (use -allowaccessmodification). This removes the
+  unused accessors and maybe inline the rest at the call sites,
+  reducing the final code size.
+  TODO(maxtroy): find ProGuard config that would work the best.
+
+  * reftypes *
+
+  When set to 'reftypes', each proto field is generated as a public Java
+  field. For primitive types, these fields use the Java reference types
+  such as java.lang.Integer instead of primitive types such as int.
+
+  In the 'reftypes' style, fields are initialized to null (or empty
+  arrays for repeated fields), and their default values are not available.
+  They are serialized over the wire based on equality to null.
+
+  The 'reftypes' mode has some additional cost due to autoboxing and usage
+  of reference types. In practice, many boxed types are cached, and so don't
+  result in object creation. However, references do take slightly more memory
+  than primitives.
+
+  The 'reftypes' mode is useful when you want to be able to serialize fields
+  with default values, or check if a field has been explicitly set to the
+  default over the wire without paying the extra method cost of the
+  'accessors' mode.
+
+  Note that if you attempt to write null to a required field in the reftypes
+  mode, serialization of the proto will cause a NullPointerException. This is
+  an intentional indicator that you must set required fields.
+
+  NOTE
+  optional_field_style=accessors or reftypes cannot be used together with
+  java_nano_generate_has=true. If you need the 'has' flag for any
+  required field (you have no reason to), you can only use
+  java_nano_generate_has=true.
+
+enum_style={c,java} (default: c)
+  Defines where to put the int constants generated from enum members.
+
+  * c *
+
+  Use C-style, so the enum constants are available at the scope where
+  the enum is defined. A file-scope enum's members are referenced like
+  'FileOuterClass.ENUM_VALUE'; a message-scope enum's members are
+  referenced as 'Message.ENUM_VALUE'. The enum name is unavailable.
+  This complies with the Micro code generator's behavior.
+
+  * java *
+
+  Use Java-style, so the enum constants are available under the enum
+  name and referenced like 'EnumName.ENUM_VALUE' (they are still int
+  constants). The enum name becomes the name of a public interface, at
+  the scope where the enum is defined. If the enum is file-scope and
+  the java_multiple_files option is on, the interface will be defined
+  in its own file. To reduce code size, this interface should not be
+  implemented and ProGuard shrinking should be used, so after the Java
+  compiler inlines all referenced enum constants into the call sites,
+  the interface remains unused and can be removed by ProGuard.
+
+
+To use nano protobufs within the Android repo:
+
+- Set 'LOCAL_PROTOC_OPTIMIZE_TYPE := nano' in your local .mk file.
+  When building a Java library or an app (package) target, the build
+  system will add the Java nano runtime library to the
+  LOCAL_STATIC_JAVA_LIBRARIES variable, so you don't need to.
+- Set 'LOCAL_PROTO_JAVA_OUTPUT_PARAMS := ...' in your local .mk file
+  for any command-line options you need. Use commas to join multiple
+  options. Write all options on the same line; avoid backslash-newline
+  or '+=', because they will introduce spaces in the middle of your
+  options and the generator is not prepared to handle them.
+- The options will be applied to *all* proto files in LOCAL_SRC_FILES
+  when you build a Java library or package. In case different options
+  are needed for different proto files, build separate Java libraries
+  and reference them in your main target. Note: you should make sure
+  that, for each separate target, all proto files imported from any
+  proto file in LOCAL_SRC_FILES are included in LOCAL_SRC_FILES. This
+  is because the generator has to assume that the imported files are
+  built using the same options, and will generate code that reference
+  the fields and enums from the imported files using the same code
+  style.
+- Hint: 'include $(CLEAR_VARS)' resets all LOCAL_ variables, including
+  the two above.
+
+To use nano protobufs outside of Android repo:
 
 - Link with the generated jar file
   <protobuf-root>java/target/protobuf-java-2.3.0-nano.jar.
@@ -484,6 +606,7 @@ java_package=src/proto/simple-data.proto|my_package,\
 java_outer_classname=src/proto/simple-data.proto|OuterName:\
 .' src/proto/simple-data.proto
 
+
 Contributing to nano:
 
 Please add/edit tests in NanoTest.java.

+ 7 - 2
java/src/main/java/com/google/protobuf/nano/WireFormatNano.java

@@ -119,6 +119,9 @@ public final class WireFormatNano {
    * <p>Generated messages will call this for unknown fields if the store_unknown_fields
    * option is on.
    *
+   * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
+   * which case we do not want to add an unknown field entry.
+   *
    * @param data a Collection in which to store the data.
    * @param input the input buffer.
    * @param tag the tag of the field.
@@ -130,11 +133,13 @@ public final class WireFormatNano {
       final CodedInputByteBufferNano input,
       final int tag) throws IOException {
     int startPos = input.getPosition();
-    boolean skip = input.skipField(tag);
+    if (!input.skipField(tag)) {
+      return false;  // This wasn't an unknown field, it's an end-group tag.
+    }
     int endPos = input.getPosition();
     byte[] bytes = input.getData(startPos, endPos - startPos);
     data.add(new UnknownFieldData(tag, bytes));
-    return skip;
+    return true;
   }
 
   /**

+ 241 - 1
java/src/test/java/com/google/protobuf/NanoTest.java

@@ -31,8 +31,12 @@
 package com.google.protobuf;
 
 import com.google.protobuf.nano.CodedInputByteBufferNano;
+import com.google.protobuf.nano.EnumClassNanoMultiple;
+import com.google.protobuf.nano.EnumClassNanos;
 import com.google.protobuf.nano.Extensions;
 import com.google.protobuf.nano.Extensions.AnotherMessage;
+import com.google.protobuf.nano.Extensions.MessageWithGroup;
+import com.google.protobuf.nano.FileScopeEnumMultiple;
 import com.google.protobuf.nano.FileScopeEnumRefNano;
 import com.google.protobuf.nano.InternalNano;
 import com.google.protobuf.nano.MessageNano;
@@ -40,15 +44,16 @@ import com.google.protobuf.nano.MessageScopeEnumRefNano;
 import com.google.protobuf.nano.MultipleImportingNonMultipleNano1;
 import com.google.protobuf.nano.MultipleImportingNonMultipleNano2;
 import com.google.protobuf.nano.MultipleNameClashNano;
+import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
 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.NanoReferenceTypes;
 import com.google.protobuf.nano.UnittestImportNano;
 import com.google.protobuf.nano.UnittestMultipleNano;
 import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
 import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
 import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
-import com.google.protobuf.nano.UnittestStringutf8Nano.StringUtf8;
 
 import junit.framework.TestCase;
 
@@ -62,6 +67,7 @@ import java.util.List;
  * @author ulas@google.com Ulas Kirazci
  */
 public class NanoTest extends TestCase {
+  @Override
   public void setUp() throws Exception {
   }
 
@@ -501,6 +507,22 @@ public class NanoTest extends TestCase {
     assertEquals(1, newMsg.optionalGroup.a);
   }
 
+  public void testNanoOptionalGroupWithUnknownFieldsEnabled() throws Exception {
+    MessageWithGroup msg = new MessageWithGroup();
+    MessageWithGroup.Group grp = new MessageWithGroup.Group();
+    grp.a = 1;
+    msg.group = grp;
+    byte [] serialized = MessageNano.toByteArray(msg);
+
+    MessageWithGroup parsed = MessageWithGroup.parseFrom(serialized);
+    assertTrue(msg.group != null);
+    assertEquals(1, msg.group.a);
+
+    byte [] serialized2 = MessageNano.toByteArray(parsed);
+    assertEquals(serialized2.length, serialized.length);
+    MessageWithGroup parsed2 = MessageWithGroup.parseFrom(serialized2);
+  }
+
   public void testNanoOptionalNestedMessage() throws Exception {
     TestAllTypesNano msg = new TestAllTypesNano();
     TestAllTypesNano.NestedMessage nestedMsg = new TestAllTypesNano.NestedMessage();
@@ -2243,6 +2265,163 @@ public class NanoTest extends TestCase {
     assertEquals(0, newMsg.id);
   }
 
+  public void testNanoWithAccessorsBasic() throws Exception {
+    TestNanoAccessors msg = new TestNanoAccessors();
+
+    // Makes sure required and repeated fields are still public fields
+    msg.id = 3;
+    msg.repeatedBytes = new byte[2][3];
+
+    // Test accessors
+    assertEquals(0, msg.getOptionalInt32());
+    assertFalse(msg.hasOptionalInt32());
+    msg.setOptionalInt32(135);
+    assertEquals(135, msg.getOptionalInt32());
+    assertTrue(msg.hasOptionalInt32());
+    msg.clearOptionalInt32();
+    assertFalse(msg.hasOptionalInt32());
+    msg.setOptionalInt32(0); // default value
+    assertTrue(msg.hasOptionalInt32());
+
+    // Test NPE
+    try {
+      msg.setOptionalBytes(null);
+      fail();
+    } catch (NullPointerException expected) {}
+    try {
+      msg.setOptionalString(null);
+      fail();
+    } catch (NullPointerException expected) {}
+    try {
+      msg.setOptionalNestedMessage(null);
+      fail();
+    } catch (NullPointerException expected) {}
+
+    // Test has bit on bytes field with defaults and clear() re-clones the default array
+    assertFalse(msg.hasDefaultBytes());
+    byte[] defaultBytes = msg.getDefaultBytes();
+    msg.setDefaultBytes(defaultBytes);
+    assertTrue(msg.hasDefaultBytes());
+    msg.clearDefaultBytes();
+    assertFalse(msg.hasDefaultBytes());
+    defaultBytes[0]++; // modify original array
+    assertFalse(Arrays.equals(defaultBytes, msg.getDefaultBytes()));
+
+    // Test has bits that require additional bit fields
+    assertFalse(msg.hasBitFieldCheck());
+    msg.setBitFieldCheck(0);
+    assertTrue(msg.hasBitFieldCheck());
+    assertFalse(msg.hasBeforeBitFieldCheck()); // checks bit field does not leak
+    assertFalse(msg.hasAfterBitFieldCheck());
+
+    // Test clear() clears has bits
+    msg.setOptionalString("hi");
+    msg.setDefaultString("there");
+    msg.clear();
+    assertFalse(msg.hasOptionalString());
+    assertFalse(msg.hasDefaultString());
+    assertFalse(msg.hasBitFieldCheck());
+  }
+
+  public void testNanoWithAccessorsParseFrom() throws Exception {
+    TestNanoAccessors msg = null;
+    // Test false on creation, after clear and upon empty parse.
+    for (int i = 0; i < 3; i++) {
+      if (i == 0) {
+        msg = new TestNanoAccessors();
+      } else if (i == 1) {
+        msg.clear();
+      } else if (i == 2) {
+        msg = TestNanoAccessors.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());
+      msg.setOptionalNestedMessage(new TestNanoAccessors.NestedMessage());
+      msg.getOptionalNestedMessage().setBb(2);
+      msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+      msg.setDefaultInt32(msg.getDefaultInt32());
+    }
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 14);
+    assertEquals(result.length, msgSerializedSize);
+
+    // Has fields true upon parse.
+    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+    assertEquals(2, newMsg.getOptionalNestedMessage().getBb());
+    assertTrue(newMsg.getOptionalNestedMessage().hasBb());
+    assertEquals(TestNanoAccessors.BAZ, newMsg.getOptionalNestedEnum());
+    assertTrue(newMsg.hasOptionalNestedEnum());
+
+    // Has field true on fields with explicit default values from wire.
+    assertTrue(newMsg.hasDefaultInt32());
+    assertEquals(41, newMsg.getDefaultInt32());
+  }
+
+  public void testNanoWithAccessorsSerialize() throws Exception {
+    TestNanoAccessors msg = new TestNanoAccessors();
+    msg.setOptionalInt32(msg.getOptionalInt32());
+    msg.setOptionalString(msg.getOptionalString());
+    msg.setOptionalBytes(msg.getOptionalBytes());
+    TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+    nestedMessage.setBb(nestedMessage.getBb());
+    msg.setOptionalNestedMessage(nestedMessage);
+    msg.setOptionalNestedEnum(msg.getOptionalNestedEnum());
+    msg.setDefaultInt32(msg.getDefaultInt32());
+    msg.setDefaultString(msg.getDefaultString());
+    msg.setDefaultBytes(msg.getDefaultBytes());
+    msg.setDefaultFloatNan(msg.getDefaultFloatNan());
+    msg.setDefaultNestedEnum(msg.getDefaultNestedEnum());
+
+    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.
+    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+    assertTrue(newMsg.hasOptionalInt32());
+    assertTrue(newMsg.hasOptionalString());
+    assertTrue(newMsg.hasOptionalBytes());
+    assertTrue(newMsg.hasOptionalNestedMessage());
+    assertTrue(newMsg.getOptionalNestedMessage().hasBb());
+    assertTrue(newMsg.hasOptionalNestedEnum());
+    assertTrue(newMsg.hasDefaultInt32());
+    assertTrue(newMsg.hasDefaultString());
+    assertTrue(newMsg.hasDefaultBytes());
+    assertTrue(newMsg.hasDefaultFloatNan());
+    assertTrue(newMsg.hasDefaultNestedEnum());
+    assertEquals(0, newMsg.getOptionalInt32());
+    assertEquals(0, newMsg.getOptionalString().length());
+    assertEquals(0, newMsg.getOptionalBytes().length);
+    assertEquals(0, newMsg.getOptionalNestedMessage().getBb());
+    assertEquals(TestNanoAccessors.FOO, newMsg.getOptionalNestedEnum());
+    assertEquals(41, newMsg.getDefaultInt32());
+    assertEquals("hello", newMsg.getDefaultString());
+    assertEquals("world", new String(newMsg.getDefaultBytes(), "UTF-8"));
+    assertEquals(TestNanoAccessors.BAR, newMsg.getDefaultNestedEnum());
+    assertEquals(Float.NaN, newMsg.getDefaultFloatNan());
+    assertEquals(0, newMsg.id);
+  }
+
+  public void testNanoJavaEnumStyle() throws Exception {
+    EnumClassNanos.EnumClassNano msg = new EnumClassNanos.EnumClassNano();
+    assertEquals(EnumClassNanos.FileScopeEnum.ONE, msg.one);
+    assertEquals(EnumClassNanos.EnumClassNano.MessageScopeEnum.TWO, msg.two);
+
+    EnumClassNanoMultiple msg2 = new EnumClassNanoMultiple();
+    assertEquals(FileScopeEnumMultiple.THREE, msg2.three);
+    assertEquals(EnumClassNanoMultiple.MessageScopeEnumMultiple.FOUR, msg2.four);
+  }
+
   /**
    * 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
@@ -2446,6 +2625,67 @@ public class NanoTest extends TestCase {
     assertEquals(123, msg.synchronized_);
   }
 
+  public void testReferenceTypesForPrimitives() throws Exception {
+    NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+
+    // Base check - when nothing is set, we serialize nothing.
+    assertHasWireData(message, false);
+
+    message.defaultBool = true;
+    assertHasWireData(message, true);
+
+    message.defaultBool = false;
+    assertHasWireData(message, true);
+
+    message.defaultBool = null;
+    assertHasWireData(message, false);
+
+    message.defaultInt32 = 5;
+    assertHasWireData(message, true);
+
+    message.defaultInt32 = null;
+    assertHasWireData(message, false);
+
+    message.defaultInt64 = 123456L;
+    assertHasWireData(message, true);
+
+    message.defaultInt64 = null;
+    assertHasWireData(message, false);
+
+    message.defaultFloat = 1f;
+    assertHasWireData(message, true);
+
+    message.defaultFloat = null;
+    assertHasWireData(message, false);
+
+    message.defaultDouble = 2.1;
+    assertHasWireData(message, true);
+
+    message.defaultDouble = null;
+    assertHasWireData(message, false);
+
+    message.defaultString = "hello";
+    assertHasWireData(message, true);
+
+    message.defaultString = null;
+    assertHasWireData(message, false);
+
+    message.defaultBytes = new byte[] { 1, 2, 3 };
+    assertHasWireData(message, true);
+
+    message.defaultBytes = null;
+    assertHasWireData(message, false);
+  }
+
+  private void assertHasWireData(MessageNano message, boolean expected) {
+    int wireLength = MessageNano.toByteArray(message).length;
+    if (expected) {
+      assertFalse(wireLength == 0);
+    } else {
+      assertEquals(0, wireLength);
+    }
+  }
+
   private <T> List<T> list(T first, T... remaining) {
     List<T> list = new ArrayList<T>();
     list.add(first);

+ 28 - 13
src/google/protobuf/compiler/javanano/javanano_enum.cc

@@ -68,25 +68,40 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Params& par
 EnumGenerator::~EnumGenerator() {}
 
 void EnumGenerator::Generate(io::Printer* printer) {
-  printer->Print("// enum $classname$\n", "classname", descriptor_->name());
-  for (int i = 0; i < canonical_values_.size(); i++) {
-    map<string, string> vars;
-    vars["name"] = RenameJavaKeywords(canonical_values_[i]->name());
-    vars["canonical_value"] = SimpleItoa(canonical_values_[i]->number());
-    printer->Print(vars,
-      "public static final int $name$ = $canonical_value$;\n");
+  printer->Print(
+      "// enum $classname$\n",
+      "classname", descriptor_->name());
+
+  // Start of container interface
+  bool use_shell_class = params_.java_enum_style();
+  if (use_shell_class) {
+    printer->Print(
+      "public interface $classname$ {\n",
+      "classname", RenameJavaKeywords(descriptor_->name()));
+    printer->Indent();
   }
 
-  // -----------------------------------------------------------------
+  // Canonical values
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    printer->Print(
+      "public static final int $name$ = $canonical_value$;\n",
+      "name", RenameJavaKeywords(canonical_values_[i]->name()),
+      "canonical_value", SimpleItoa(canonical_values_[i]->number()));
+  }
 
+  // Aliases
   for (int i = 0; i < aliases_.size(); i++) {
-    map<string, string> vars;
-    vars["name"] = RenameJavaKeywords(aliases_[i].value->name());
-    vars["canonical_name"] = aliases_[i].canonical_value->name();
-    printer->Print(vars,
-      "public static final int $name$ = $canonical_name$;\n");
+    printer->Print(
+      "public static final int $name$ = $canonical_name$;\n",
+      "name", RenameJavaKeywords(aliases_[i].value->name()),
+      "canonical_name", RenameJavaKeywords(aliases_[i].canonical_value->name()));
   }
 
+  // End of container interface
+  if (use_shell_class) {
+    printer->Outdent();
+    printer->Print("}\n");
+  }
   printer->Print("\n");
 }
 

+ 96 - 6
src/google/protobuf/compiler/javanano/javanano_enum_field.cc

@@ -58,8 +58,16 @@ void SetEnumVariables(const Params& params,
   (*variables)["capitalized_name"] =
     RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
   (*variables)["number"] = SimpleItoa(descriptor->number());
-  (*variables)["type"] = "int";
-  (*variables)["default"] = DefaultValue(params, descriptor);
+  if (params.use_reference_types_for_primitives()
+      && !descriptor->is_repeated()) {
+    (*variables)["type"] = "java.lang.Integer";
+    (*variables)["default"] = "null";
+  } else {
+    (*variables)["type"] = "int";
+    (*variables)["default"] = DefaultValue(params, descriptor);
+  }
+  (*variables)["repeated_default"] =
+      "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
   (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
       internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
@@ -81,7 +89,7 @@ EnumFieldGenerator::~EnumFieldGenerator() {}
 void EnumFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "public int $name$ = $default$;\n");
+    "public $type$ $name$ = $default$;\n");
 
   if (params_.generate_has()) {
     printer->Print(variables_,
@@ -90,7 +98,18 @@ GenerateMembers(io::Printer* printer) const {
 }
 
 void EnumFieldGenerator::
-GenerateParsingCode(io::Printer* printer) const {
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$ = $default$;\n");
+
+  if (params_.generate_has()) {
+    printer->Print(variables_,
+      "has$capitalized_name$ = false;\n");
+  }
+}
+
+void EnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
   printer->Print(variables_,
     "  this.$name$ = input.readInt32();\n");
 
@@ -146,6 +165,71 @@ string EnumFieldGenerator::GetBoxedType() const {
 
 // ===================================================================
 
+AccessorEnumFieldGenerator::
+AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
+    const Params& params, int has_bit_index)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetEnumVariables(params, descriptor, &variables_);
+  SetBitOperationVariables("has", has_bit_index, &variables_);
+}
+
+AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
+
+void AccessorEnumFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private int $name$_ = $default$;\n"
+    "public int get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n"
+    "public void set$capitalized_name$(int value) {\n"
+    "  $name$_ = value;\n"
+    "  $set_has$;\n"
+    "}\n"
+    "public boolean has$capitalized_name$() {\n"
+    "  return $get_has$;\n"
+    "}\n"
+    "public void clear$capitalized_name$() {\n"
+    "  $name$_ = $default$;\n"
+    "  $clear_has$;\n"
+    "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = $default$;\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "set$capitalized_name$(input.readInt32());\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  output.writeInt32($number$, $name$_);\n"
+    "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+    "    .computeInt32Size($number$, $name$_);\n"
+    "}\n");
+}
+
+string AccessorEnumFieldGenerator::GetBoxedType() const {
+  return ClassName(params_, descriptor_->enum_type());
+}
+
+// ===================================================================
+
 RepeatedEnumFieldGenerator::
 RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
   : FieldGenerator(params), descriptor_(descriptor) {
@@ -157,7 +241,7 @@ RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
 void RepeatedEnumFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "public int[] $name$ = com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY;\n");
+    "public $type$[] $name$ = $repeated_default$;\n");
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
@@ -165,7 +249,13 @@ GenerateMembers(io::Printer* printer) const {
 }
 
 void RepeatedEnumFieldGenerator::
-GenerateParsingCode(io::Printer* printer) const {
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$ = $repeated_default$;\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
   // First, figure out the length of the array, then parse.
   if (descriptor_->options().packed()) {
     printer->Print(variables_,

+ 26 - 2
src/google/protobuf/compiler/javanano/javanano_enum_field.h

@@ -51,7 +51,8 @@ class EnumFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GenerateMembers(io::Printer* printer) const;
-  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
 
@@ -64,6 +65,28 @@ class EnumFieldGenerator : public FieldGenerator {
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
 };
 
+class AccessorEnumFieldGenerator : public FieldGenerator {
+ public:
+  explicit AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
+      const Params& params, int has_bit_index);
+  ~AccessorEnumFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorEnumFieldGenerator);
+};
+
 class RepeatedEnumFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
@@ -71,7 +94,8 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GenerateMembers(io::Printer* printer) const;
-  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
 

+ 23 - 3
src/google/protobuf/compiler/javanano/javanano_field.cc

@@ -53,16 +53,21 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Params
     extension_generators_(
       new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
 
+  int next_has_bit_index = 0;
   // Construct all the FieldGenerators.
   for (int i = 0; i < descriptor->field_count(); i++) {
-    field_generators_[i].reset(MakeGenerator(descriptor->field(i), params));
+    field_generators_[i].reset(
+        MakeGenerator(descriptor->field(i), params, &next_has_bit_index));
   }
   for (int i = 0; i < descriptor->extension_count(); i++) {
-    extension_generators_[i].reset(MakeGenerator(descriptor->extension(i), params));
+    extension_generators_[i].reset(
+        MakeGenerator(descriptor->extension(i), params, &next_has_bit_index));
   }
+  total_bits_ = next_has_bit_index;
 }
 
-FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, const Params &params) {
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
+    const Params &params, int* next_has_bit_index) {
   if (field->is_repeated()) {
     switch (GetJavaType(field)) {
       case JAVATYPE_MESSAGE:
@@ -72,6 +77,21 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, c
       default:
         return new RepeatedPrimitiveFieldGenerator(field, params);
     }
+  } else if (params.optional_field_accessors() && field->is_optional()) {
+    // We need a has-bit for each primitive/enum field because their default
+    // values could be same as explicitly set values. But we don't need it
+    // for a message field because they have no defaults and Nano uses 'null'
+    // for unset messages, which cannot be set explicitly.
+    switch (GetJavaType(field)) {
+      case JAVATYPE_MESSAGE:
+        return new AccessorMessageFieldGenerator(field, params);
+      case JAVATYPE_ENUM:
+        return new AccessorEnumFieldGenerator(
+            field, params, (*next_has_bit_index)++);
+      default:
+        return new AccessorPrimitiveFieldGenerator(
+            field, params, (*next_has_bit_index)++);
+    }
   } else {
     switch (GetJavaType(field)) {
       case JAVATYPE_MESSAGE:

+ 6 - 2
src/google/protobuf/compiler/javanano/javanano_field.h

@@ -58,7 +58,8 @@ class FieldGenerator {
   virtual ~FieldGenerator();
 
   virtual void GenerateMembers(io::Printer* printer) const = 0;
-  virtual void GenerateParsingCode(io::Printer* printer) const = 0;
+  virtual void GenerateClearCode(io::Printer* printer) const = 0;
+  virtual void GenerateMergingCode(io::Printer* printer) const = 0;
   virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
 
@@ -78,13 +79,16 @@ class FieldGeneratorMap {
 
   const FieldGenerator& get(const FieldDescriptor* field) const;
   const FieldGenerator& get_extension(int index) const;
+  int total_bits() const { return total_bits_; }
 
  private:
   const Descriptor* descriptor_;
   scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
   scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
+  int total_bits_;
 
-  static FieldGenerator* MakeGenerator(const FieldDescriptor* field, const Params &params);
+  static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+      const Params &params, int* next_has_bit_index);
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
 };

+ 15 - 0
src/google/protobuf/compiler/javanano/javanano_file.cc

@@ -138,6 +138,13 @@ bool FileGenerator::Validate(string* error) {
       found_conflict = true;
     }
   }
+  if (params_.java_enum_style()) {
+    for (int i = 0; !found_conflict && i < file_->enum_type_count(); i++) {
+      if (file_->enum_type(i)->name() == classname_) {
+        found_conflict = true;
+      }
+    }
+  }
   if (found_conflict) {
     error->assign(file_->name());
     error->append(
@@ -237,6 +244,14 @@ void FileGenerator::GenerateSiblings(const string& package_dir,
                                         file_->message_type(i),
                                         output_directory, file_list, params_);
     }
+
+    if (params_.java_enum_style()) {
+      for (int i = 0; i < file_->enum_type_count(); i++) {
+        GenerateSibling<EnumGenerator>(package_dir, java_package_,
+                                       file_->enum_type(i),
+                                       output_directory, file_list, params_);
+      }
+    }
   }
 }
 

+ 18 - 1
src/google/protobuf/compiler/javanano/javanano_generator.cc

@@ -119,12 +119,29 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file,
     } else if (options[i].first == "java_multiple_files") {
       params.set_override_java_multiple_files(options[i].second == "true");
     } else if (options[i].first == "java_nano_generate_has") {
-        params.set_generate_has(options[i].second == "true");
+      params.set_generate_has(options[i].second == "true");
+    } else if (options[i].first == "enum_style") {
+      params.set_java_enum_style(options[i].second == "java");
+    } else if (options[i].first == "optional_field_style") {
+      params.set_optional_field_accessors(options[i].second == "accessors");
+      params.set_use_reference_types_for_primitives(options[i].second == "reftypes");
     } else {
       *error = "Ignore unknown javanano generator option: " + options[i].first;
     }
   }
 
+  // Check illegal parameter combinations
+  // Note: the enum-like optional_field_style generator param ensures
+  // that we can never have illegal combinations of field styles
+  // (e.g. reftypes and accessors can't be on at the same time).
+  if (params.generate_has()
+      && (params.optional_field_accessors()
+          || params.use_reference_types_for_primitives())) {
+    error->assign("java_nano_generate_has=true cannot be used in conjunction"
+        " with optional_field_style=accessors or optional_field_style=reftypes");
+    return false;
+  }
+
   // -----------------------------------------------------------------
 
   FileGenerator file_generator(file, params);

+ 110 - 6
src/google/protobuf/compiler/javanano/javanano_helpers.cc

@@ -197,12 +197,23 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) {
 }
 
 bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) {
-  // Enums and extensions need the outer class as the scope.
-  if (file->enum_type_count() != 0 || file->extension_count() != 0) {
+  // If java_multiple_files is false, the outer class is always needed.
+  if (!params.java_multiple_files(file->name())) {
     return true;
   }
-  // Messages need the outer class only if java_multiple_files is false.
-  return !params.java_multiple_files(file->name());
+
+  // File-scope extensions need the outer class as the scope.
+  if (file->extension_count() != 0) {
+    return true;
+  }
+
+  // If container interfaces are not generated, file-scope enums need the
+  // outer class as the scope.
+  if (file->enum_type_count() != 0 && !params.java_enum_style()) {
+    return true;
+  }
+
+  return false;
 }
 
 string ToJavaName(const Params& params, const string& name, bool is_class,
@@ -228,9 +239,14 @@ string ClassName(const Params& params, const FileDescriptor* descriptor) {
 }
 
 string ClassName(const Params& params, const EnumDescriptor* descriptor) {
-  // An enum's class name is the enclosing message's class name or the outer
-  // class name.
   const Descriptor* parent = descriptor->containing_type();
+  // When using Java enum style, an enum's class name contains the enum name.
+  // Use the standard ToJavaName translation.
+  if (params.java_enum_style()) {
+    return ToJavaName(params, descriptor->name(), true, parent,
+                      descriptor->file());
+  }
+  // Otherwise the enum members are accessed from the enclosing class.
   if (parent != NULL) {
     return ClassName(params, parent);
   } else {
@@ -341,6 +357,10 @@ string DefaultValue(const Params& params, const FieldDescriptor* field) {
     return EmptyArrayName(params, field);
   }
 
+  if (params.use_reference_types_for_primitives()) {
+    return "null";
+  }
+
   // Switch on cpp_type since we need to know which default_value_* method
   // of FieldDescriptor to call.
   switch (field->cpp_type()) {
@@ -407,6 +427,90 @@ string DefaultValue(const Params& params, const FieldDescriptor* field) {
   return "";
 }
 
+
+static const char* kBitMasks[] = {
+  "0x00000001",
+  "0x00000002",
+  "0x00000004",
+  "0x00000008",
+  "0x00000010",
+  "0x00000020",
+  "0x00000040",
+  "0x00000080",
+
+  "0x00000100",
+  "0x00000200",
+  "0x00000400",
+  "0x00000800",
+  "0x00001000",
+  "0x00002000",
+  "0x00004000",
+  "0x00008000",
+
+  "0x00010000",
+  "0x00020000",
+  "0x00040000",
+  "0x00080000",
+  "0x00100000",
+  "0x00200000",
+  "0x00400000",
+  "0x00800000",
+
+  "0x01000000",
+  "0x02000000",
+  "0x04000000",
+  "0x08000000",
+  "0x10000000",
+  "0x20000000",
+  "0x40000000",
+  "0x80000000",
+};
+
+string GetBitFieldName(int index) {
+  string var_name = "bitField";
+  var_name += SimpleItoa(index);
+  var_name += "_";
+  return var_name;
+}
+
+string GetBitFieldNameForBit(int bit_index) {
+  return GetBitFieldName(bit_index / 32);
+}
+
+string GenerateGetBit(int bit_index) {
+  string var_name = GetBitFieldNameForBit(bit_index);
+  int bit_in_var_index = bit_index % 32;
+
+  string mask = kBitMasks[bit_in_var_index];
+  string result = "((" + var_name + " & " + mask + ") == " + mask + ")";
+  return result;
+}
+
+string GenerateSetBit(int bit_index) {
+  string var_name = GetBitFieldNameForBit(bit_index);
+  int bit_in_var_index = bit_index % 32;
+
+  string mask = kBitMasks[bit_in_var_index];
+  string result = var_name + " |= " + mask;
+  return result;
+}
+
+string GenerateClearBit(int bit_index) {
+  string var_name = GetBitFieldNameForBit(bit_index);
+  int bit_in_var_index = bit_index % 32;
+
+  string mask = kBitMasks[bit_in_var_index];
+  string result = var_name + " = (" + var_name + " & ~" + mask + ")";
+  return result;
+}
+
+void SetBitOperationVariables(const string name,
+    int bitIndex, map<string, string>* variables) {
+  (*variables)["get_" + name] = GenerateGetBit(bitIndex);
+  (*variables)["set_" + name] = GenerateSetBit(bitIndex);
+  (*variables)["clear_" + name] = GenerateClearBit(bitIndex);
+}
+
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf

+ 30 - 0
src/google/protobuf/compiler/javanano/javanano_helpers.h

@@ -138,6 +138,36 @@ string EmptyArrayName(const Params& params, const FieldDescriptor* field);
 
 string DefaultValue(const Params& params, const FieldDescriptor* field);
 
+
+// Methods for shared bitfields.
+
+// Gets the name of the shared bitfield for the given index.
+string GetBitFieldName(int index);
+
+// Gets the name of the shared bitfield for the given bit index.
+// Effectively, GetBitFieldName(bit_index / 32)
+string GetBitFieldNameForBit(int bit_index);
+
+// Generates the java code for the expression that returns the boolean value
+// of the bit of the shared bitfields for the given bit index.
+// Example: "((bitField1_ & 0x04) == 0x04)"
+string GenerateGetBit(int bit_index);
+
+// Generates the java code for the expression that sets the bit of the shared
+// bitfields for the given bit index.
+// Example: "bitField1_ = (bitField1_ | 0x04)"
+string GenerateSetBit(int bit_index);
+
+// Generates the java code for the expression that clears the bit of the shared
+// bitfields for the given bit index.
+// Example: "bitField1_ = (bitField1_ & ~0x04)"
+string GenerateClearBit(int bit_index);
+
+// Sets the 'get_*', 'set_*' and 'clear_*' variables, where * is the given bit
+// field name, to the appropriate Java expressions for the given bit index.
+void SetBitOperationVariables(const string name,
+    int bitIndex, map<string, string>* variables);
+
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf

+ 18 - 27
src/google/protobuf/compiler/javanano/javanano_message.cc

@@ -137,9 +137,9 @@ void MessageGenerator::Generate(io::Printer* printer) {
   // warnings here in the class declaration.
   printer->Print(
     "@SuppressWarnings(\"hiding\")\n"
-    "public $modifiers$ final class $classname$ extends\n"
+    "public $modifiers$final class $classname$ extends\n"
     "    com.google.protobuf.nano.MessageNano {\n",
-    "modifiers", is_own_file ? "" : "static",
+    "modifiers", is_own_file ? "" : "static ",
     "classname", descriptor_->name());
   printer->Indent();
   printer->Print(
@@ -167,6 +167,13 @@ void MessageGenerator::Generate(io::Printer* printer) {
     MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
   }
 
+  // Integers for bit fields
+  int totalInts = (field_generators_.total_bits() + 31) / 32;
+  for (int i = 0; i < totalInts; i++) {
+    printer->Print("private int $bit_field_name$;\n",
+      "bit_field_name", GetBitFieldName(i));
+  }
+
   // Fields
   for (int i = 0; i < descriptor_->field_count(); i++) {
     PrintFieldComment(printer, descriptor_->field(i));
@@ -327,7 +334,7 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
       "tag", SimpleItoa(tag));
     printer->Indent();
 
-    field_generators_.get(field).GenerateParsingCode(printer);
+    field_generators_.get(field).GenerateMergingCode(printer);
 
     printer->Outdent();
     printer->Print(
@@ -376,33 +383,17 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
     "classname", descriptor_->name());
   printer->Indent();
 
+  // Clear bit fields.
+  int totalInts = (field_generators_.total_bits() + 31) / 32;
+  for (int i = 0; i < totalInts; i++) {
+    printer->Print("$bit_field_name$ = 0;\n",
+      "bit_field_name", GetBitFieldName(i));
+  }
+
   // Call clear for all of the fields.
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
-
-    if (field->type() == FieldDescriptor::TYPE_BYTES &&
-        !field->default_value_string().empty()) {
-      // Need to clone the default value because it is of a mutable
-      // type.
-      printer->Print(
-        "$name$ = $default$.clone();\n",
-        "name", RenameJavaKeywords(UnderscoresToCamelCase(field)),
-        "default", DefaultValue(params_, field));
-    } else {
-      printer->Print(
-        "$name$ = $default$;\n",
-        "name", RenameJavaKeywords(UnderscoresToCamelCase(field)),
-        "default", DefaultValue(params_, field));
-    }
-
-    if (params_.generate_has() &&
-        field->label() != FieldDescriptor::LABEL_REPEATED &&
-        field->type() != FieldDescriptor::TYPE_GROUP &&
-        field->type() != FieldDescriptor::TYPE_MESSAGE) {
-      printer->Print(
-        "has$capitalized_name$ = false;\n",
-        "capitalized_name", UnderscoresToCapitalizedCamelCase(field));
-    }
+    field_generators_.get(field).GenerateClearCode(printer);
   }
 
   // Clear unknown fields.

+ 92 - 3
src/google/protobuf/compiler/javanano/javanano_message_field.cc

@@ -88,9 +88,17 @@ GenerateMembers(io::Printer* printer) const {
 }
 
 void MessageFieldGenerator::
-GenerateParsingCode(io::Printer* printer) const {
+GenerateClearCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "this.$name$ = new $type$();\n");
+    "$name$ = null;\n");
+}
+
+void MessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ == null) {\n"
+    "  this.$name$ = new $type$();\n"
+    "}");
 
   if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
@@ -124,6 +132,81 @@ string MessageFieldGenerator::GetBoxedType() const {
 
 // ===================================================================
 
+AccessorMessageFieldGenerator::
+AccessorMessageFieldGenerator(
+    const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetMessageVariables(params, descriptor, &variables_);
+}
+
+AccessorMessageFieldGenerator::~AccessorMessageFieldGenerator() {}
+
+void AccessorMessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $type$ $name$_ = null;\n"
+    "public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n"
+    "public void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new java.lang.NullPointerException();\n"
+    "  }\n"
+    "  $name$_ = value;\n"
+    "}\n"
+    "public boolean has$capitalized_name$() {\n"
+    "  return $name$_ != null;\n"
+    "}\n"
+    "public void clear$capitalized_name$() {\n"
+    "  $name$_ = null;\n"
+    "}\n");
+}
+
+void AccessorMessageFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = null;\n");
+}
+
+void AccessorMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!has$capitalized_name$()) {\n"
+    "  set$capitalized_name$(new $type$());\n"
+    "}");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+      "input.readGroup($name$_, $number$);\n");
+  } else {
+    printer->Print(variables_,
+      "input.readMessage($name$_);\n");
+  }
+}
+
+void AccessorMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  output.write$group_or_message$($number$, $name$_);\n"
+    "}\n");
+}
+
+void AccessorMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+    "    .compute$group_or_message$Size($number$, $name$_);\n"
+    "}\n");
+}
+
+string AccessorMessageFieldGenerator::GetBoxedType() const {
+  return ClassName(params_, descriptor_->message_type());
+}
+
+// ===================================================================
+
 RepeatedMessageFieldGenerator::
 RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
   : FieldGenerator(params), descriptor_(descriptor) {
@@ -139,7 +222,13 @@ GenerateMembers(io::Printer* printer) const {
 }
 
 void RepeatedMessageFieldGenerator::
-GenerateParsingCode(io::Printer* printer) const {
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$ = $type$.EMPTY_ARRAY;\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
   // First, figure out the length of the array, then parse.
   printer->Print(variables_,
     "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n"

+ 26 - 2
src/google/protobuf/compiler/javanano/javanano_message_field.h

@@ -51,7 +51,8 @@ class MessageFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GenerateMembers(io::Printer* printer) const;
-  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
 
@@ -64,6 +65,28 @@ class MessageFieldGenerator : public FieldGenerator {
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
 };
 
+class AccessorMessageFieldGenerator : public FieldGenerator {
+ public:
+  explicit AccessorMessageFieldGenerator(
+      const FieldDescriptor* descriptor, const Params& params);
+  ~AccessorMessageFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorMessageFieldGenerator);
+};
+
 class RepeatedMessageFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
@@ -72,7 +95,8 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GenerateMembers(io::Printer* printer) const;
-  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
 

+ 27 - 1
src/google/protobuf/compiler/javanano/javanano_params.h

@@ -58,6 +58,9 @@ class Params {
   NameMap java_outer_classnames_;
   NameSet java_multiple_files_;
   bool generate_has_;
+  bool java_enum_style_;
+  bool optional_field_accessors_;
+  bool use_reference_types_for_primitives_;
 
  public:
   Params(const string & base_name) :
@@ -65,7 +68,10 @@ class Params {
     base_name_(base_name),
     override_java_multiple_files_(JAVANANO_MUL_UNSET),
     store_unknown_fields_(false),
-    generate_has_(false) {
+    generate_has_(false),
+    java_enum_style_(false),
+    optional_field_accessors_(false),
+    use_reference_types_for_primitives_(false) {
   }
 
   const string& base_name() const {
@@ -160,6 +166,26 @@ class Params {
     return generate_has_;
   }
 
+  void set_java_enum_style(bool value) {
+    java_enum_style_ = value;
+  }
+  bool java_enum_style() const {
+    return java_enum_style_;
+  }
+
+  void set_optional_field_accessors(bool value) {
+    optional_field_accessors_ = value;
+  }
+  bool optional_field_accessors() const {
+    return optional_field_accessors_;
+  }
+
+  void set_use_reference_types_for_primitives(bool value) {
+    use_reference_types_for_primitives_ = value;
+  }
+  bool use_reference_types_for_primitives() const {
+    return use_reference_types_for_primitives_;
+  }
 };
 
 }  // namespace javanano

+ 115 - 22
src/google/protobuf/compiler/javanano/javanano_primitive_field.cc

@@ -245,7 +245,12 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params param
   (*variables)["capitalized_name"] =
     RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
   (*variables)["number"] = SimpleItoa(descriptor->number());
-  (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+  if (params.use_reference_types_for_primitives()
+      && !descriptor->is_repeated()) {
+    (*variables)["type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+  } else {
+    (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+  }
   (*variables)["default"] = DefaultValue(params, descriptor);
   (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
   // For C++-string types (string and bytes), we might need to have
@@ -254,12 +259,14 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params param
   // once into a "private static final" field and re-use that from
   // then on.
   if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
-      !descriptor->default_value_string().empty()) {
+      !descriptor->default_value_string().empty() &&
+      !params.use_reference_types_for_primitives()) {
     string default_value;
     if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
       default_value = strings::Substitute(
           "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
           CEscape(descriptor->default_value_string()));
+      (*variables)["default_copy_if_needed"] = (*variables)["default"] + ".clone()";
     } else {
       if (AllAscii(descriptor->default_value_string())) {
         // All chars are ASCII.  In this case CEscape() works fine.
@@ -269,22 +276,17 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params param
             "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
             CEscape(descriptor->default_value_string()));
       }
+      (*variables)["default_copy_if_needed"] = (*variables)["default"];
     }
     (*variables)["default_constant_value"] = default_value;
+  } else {
+    (*variables)["default_copy_if_needed"] = (*variables)["default"];
   }
   (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
   (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
   (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
       WireFormat::TagSize(descriptor->number(), descriptor->type()));
-  if (IsReferenceType(GetJavaType(descriptor))) {
-    (*variables)["null_check"] =
-        "  if (value == null) {\n"
-        "    throw new NullPointerException();\n"
-        "  }\n";
-  } else {
-    (*variables)["null_check"] = "";
-  }
   int fixed_size = FixedSize(descriptor->type());
   if (fixed_size != -1) {
     (*variables)["fixed_size"] = SimpleItoa(fixed_size);
@@ -310,18 +312,11 @@ GenerateMembers(io::Printer* printer) const {
     // Those primitive types that need a saved default.
     printer->Print(variables_,
       "private static final $type$ $default_constant$ = $default_constant_value$;\n");
-    if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
-      printer->Print(variables_,
-        "public $type$ $name$ = $default$.clone();\n");
-    } else {
-      printer->Print(variables_,
-        "public $type$ $name$ = $default$;\n");
-    }
-  } else {
-    printer->Print(variables_,
-      "public $type$ $name$ = $default$;\n");
   }
 
+  printer->Print(variables_,
+    "public $type$ $name$ = $default_copy_if_needed$;\n");
+
   if (params_.generate_has()) {
     printer->Print(variables_,
       "public boolean has$capitalized_name$ = false;\n");
@@ -329,7 +324,18 @@ GenerateMembers(io::Printer* printer) const {
 }
 
 void PrimitiveFieldGenerator::
-GenerateParsingCode(io::Printer* printer) const {
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$ = $default_copy_if_needed$;\n");
+
+  if (params_.generate_has()) {
+    printer->Print(variables_,
+      "has$capitalized_name$ = false;\n");
+  }
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
   printer->Print(variables_,
     "this.$name$ = input.read$capitalized_type$();\n");
 
@@ -341,6 +347,13 @@ GenerateParsingCode(io::Printer* printer) const {
 
 void PrimitiveFieldGenerator::
 GenerateSerializationConditional(io::Printer* printer) const {
+  if (params_.use_reference_types_for_primitives()) {
+    // For reference type mode, serialize based on equality
+    // to null.
+    printer->Print(variables_,
+      "if (this.$name$ != null) {\n");
+    return;
+  }
   if (params_.generate_has()) {
     printer->Print(variables_,
       "if (has$capitalized_name$ || ");
@@ -397,6 +410,80 @@ string PrimitiveFieldGenerator::GetBoxedType() const {
 
 // ===================================================================
 
+AccessorPrimitiveFieldGenerator::
+AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+     const Params& params, int has_bit_index)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetPrimitiveVariables(descriptor, params, &variables_);
+  SetBitOperationVariables("has", has_bit_index, &variables_);
+}
+
+AccessorPrimitiveFieldGenerator::~AccessorPrimitiveFieldGenerator() {}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  if (variables_.find("default_constant_value") != variables_.end()) {
+    printer->Print(variables_,
+      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
+  }
+  printer->Print(variables_,
+    "private $type$ $name$_ = $default_copy_if_needed$;\n"
+    "public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n"
+    "public void set$capitalized_name$($type$ value) {\n");
+  if (IsReferenceType(GetJavaType(descriptor_))) {
+    printer->Print(variables_,
+      "  if (value == null) throw new java.lang.NullPointerException();\n");
+  }
+  printer->Print(variables_,
+    "  $name$_ = value;\n"
+    "  $set_has$;\n"
+    "}\n"
+    "public boolean has$capitalized_name$() {\n"
+    "  return $get_has$;\n"
+    "}\n"
+    "public void clear$capitalized_name$() {\n"
+    "  $name$_ = $default_copy_if_needed$;\n"
+    "  $clear_has$;\n"
+    "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = $default_copy_if_needed$;\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "set$capitalized_name$(input.read$capitalized_type$());\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  output.write$capitalized_type$($number$, $name$_);\n"
+    "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+    "      .compute$capitalized_type$Size($number$, $name$_);\n"
+    "}\n");
+}
+
+string AccessorPrimitiveFieldGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
 RepeatedPrimitiveFieldGenerator::
 RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
   : FieldGenerator(params), descriptor_(descriptor) {
@@ -412,7 +499,13 @@ GenerateMembers(io::Printer* printer) const {
 }
 
 void RepeatedPrimitiveFieldGenerator::
-GenerateParsingCode(io::Printer* printer) const {
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$ = $default$;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
   // First, figure out the length of the array, then parse.
   if (descriptor_->options().packed()) {
     printer->Print(variables_,

+ 26 - 2
src/google/protobuf/compiler/javanano/javanano_primitive_field.h

@@ -51,7 +51,8 @@ class PrimitiveFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GenerateMembers(io::Printer* printer) const;
-  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
 
@@ -66,6 +67,28 @@ class PrimitiveFieldGenerator : public FieldGenerator {
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
 };
 
+class AccessorPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+  explicit AccessorPrimitiveFieldGenerator( const FieldDescriptor* descriptor,
+      const Params &params, int has_bit_index);
+  ~AccessorPrimitiveFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorPrimitiveFieldGenerator);
+};
+
 class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
@@ -73,7 +96,8 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GenerateMembers(io::Printer* printer) const;
-  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
 

+ 116 - 0
src/google/protobuf/unittest_accessors_nano.proto

@@ -0,0 +1,116 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoAccessorsOuterClass";
+
+message TestNanoAccessors {
+
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional int32  optional_int32    =  1;
+  optional string optional_string   = 14;
+  optional bytes  optional_bytes    = 15;
+
+  optional NestedMessage optional_nested_message = 18;
+
+  optional NestedEnum optional_nested_enum = 21;
+
+  // Repeated
+  repeated int32  repeated_int32    = 31;
+  repeated string repeated_string   = 44;
+  repeated bytes  repeated_bytes    = 45;
+
+  repeated NestedMessage repeated_nested_message  = 48;
+
+  repeated NestedEnum repeated_nested_enum  = 51;
+
+  // Singular with defaults
+  optional int32  default_int32    = 61 [default =  41    ];
+  optional string default_string   = 74 [default = "hello"];
+  optional bytes  default_bytes    = 75 [default = "world"];
+
+  optional float default_float_nan = 99  [default =  nan];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+  // Required
+  required int32 id = 86;
+
+  // Add enough optional fields to make 2 bit fields in total
+  optional int32 filler100 = 100;
+  optional int32 filler101 = 101;
+  optional int32 filler102 = 102;
+  optional int32 filler103 = 103;
+  optional int32 filler104 = 104;
+  optional int32 filler105 = 105;
+  optional int32 filler106 = 106;
+  optional int32 filler107 = 107;
+  optional int32 filler108 = 108;
+  optional int32 filler109 = 109;
+  optional int32 filler110 = 110;
+  optional int32 filler111 = 111;
+  optional int32 filler112 = 112;
+  optional int32 filler113 = 113;
+  optional int32 filler114 = 114;
+  optional int32 filler115 = 115;
+  optional int32 filler116 = 116;
+  optional int32 filler117 = 117;
+  optional int32 filler118 = 118;
+  optional int32 filler119 = 119;
+  optional int32 filler120 = 120;
+  optional int32 filler121 = 121;
+  optional int32 filler122 = 122;
+  optional int32 filler123 = 123;
+  optional int32 filler124 = 124;
+  optional int32 filler125 = 125;
+  optional int32 filler126 = 126;
+  optional int32 filler127 = 127;
+  optional int32 filler128 = 128;
+  optional int32 filler129 = 129;
+  optional int32 filler130 = 130;
+
+  optional int32 before_bit_field_check = 139;
+  optional int32 bit_field_check = 140;
+  optional int32 after_bit_field_check = 141;
+}

+ 48 - 0
src/google/protobuf/unittest_enum_class_multiple_nano.proto

@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+enum FileScopeEnumMultiple {
+  THREE = 3;
+}
+
+message EnumClassNanoMultiple {
+  enum MessageScopeEnumMultiple {
+    FOUR = 4;
+  }
+  optional FileScopeEnumMultiple three = 3 [ default = THREE ];
+  optional MessageScopeEnumMultiple four = 4 [ default = FOUR ];
+}

+ 48 - 0
src/google/protobuf/unittest_enum_class_nano.proto

@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "EnumClassNanos";
+
+enum FileScopeEnum {
+  ONE = 1;
+}
+
+message EnumClassNano {
+  enum MessageScopeEnum {
+    TWO = 2;
+  }
+  optional FileScopeEnum one = 1 [ default = ONE ];
+  optional MessageScopeEnum two = 2 [ default = TWO ];
+}

+ 6 - 0
src/google/protobuf/unittest_extension_nano.proto

@@ -42,3 +42,9 @@ message ContainerMessage {
     optional bool another_thing = 100;
   }
 }
+
+message MessageWithGroup {
+  optional group Group = 1 {
+    optional int32 a = 2;
+  }
+}

+ 116 - 0
src/google/protobuf/unittest_reference_types_nano.proto

@@ -0,0 +1,116 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoReferenceTypes";
+
+message TestAllTypesNano {
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  message NestedMessage {
+    optional int32 foo = 1;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage      optional_nested_message  = 18;
+
+  optional NestedEnum      optional_nested_enum     = 21;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage      repeated_nested_message  = 48;
+
+  repeated NestedEnum      repeated_nested_enum  = 51;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  // Repeated packed
+  repeated    int32 repeated_packed_int32    = 87 [packed=true];
+  repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
+
+  repeated NestedEnum repeated_packed_nested_enum  = 89 [packed=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+
+  optional  float default_float_inf      = 97  [default =  inf];
+  optional  float default_float_neg_inf  = 98  [default = -inf];
+  optional  float default_float_nan      = 99  [default =  nan];
+  optional double default_double_inf     = 100 [default =  inf];
+  optional double default_double_neg_inf = 101 [default = -inf];
+  optional double default_double_nan     = 102 [default =  nan];
+
+}
+
+message ForeignMessageNano {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumNano {
+  FOREIGN_NANO_FOO = 4;
+  FOREIGN_NANO_BAR = 5;
+  FOREIGN_NANO_BAZ = 6;
+}
+