Sfoglia il codice sorgente

down integrate to svn

jieluo@google.com 11 anni fa
parent
commit
4de8f55113
100 ha cambiato i file con 9967 aggiunte e 3755 eliminazioni
  1. 17 5
      Makefile.am
  2. 1 1
      examples/Makefile
  3. 10 0
      java/pom.xml
  4. 133 597
      java/src/main/java/com/google/protobuf/AbstractMessage.java
  5. 18 6
      java/src/main/java/com/google/protobuf/AbstractMessageLite.java
  6. 0 8
      java/src/main/java/com/google/protobuf/AbstractParser.java
  7. 52 0
      java/src/main/java/com/google/protobuf/ByteString.java
  8. 531 140
      java/src/main/java/com/google/protobuf/CodedInputStream.java
  9. 208 22
      java/src/main/java/com/google/protobuf/CodedOutputStream.java
  10. 316 48
      java/src/main/java/com/google/protobuf/Descriptors.java
  11. 110 8
      java/src/main/java/com/google/protobuf/DynamicMessage.java
  12. 96 0
      java/src/main/java/com/google/protobuf/Extension.java
  13. 156 30
      java/src/main/java/com/google/protobuf/ExtensionRegistry.java
  14. 73 27
      java/src/main/java/com/google/protobuf/FieldSet.java
  15. 331 57
      java/src/main/java/com/google/protobuf/GeneratedMessage.java
  16. 190 38
      java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  17. 238 0
      java/src/main/java/com/google/protobuf/Internal.java
  18. 8 0
      java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  19. 25 81
      java/src/main/java/com/google/protobuf/LazyField.java
  20. 202 13
      java/src/main/java/com/google/protobuf/LazyStringArrayList.java
  21. 96 14
      java/src/main/java/com/google/protobuf/LazyStringList.java
  22. 19 6
      java/src/main/java/com/google/protobuf/LiteralByteString.java
  23. 7 0
      java/src/main/java/com/google/protobuf/Message.java
  24. 1 0
      java/src/main/java/com/google/protobuf/MessageLite.java
  25. 15 1
      java/src/main/java/com/google/protobuf/MessageOrBuilder.java
  26. 931 0
      java/src/main/java/com/google/protobuf/MessageReflection.java
  27. 2 0
      java/src/main/java/com/google/protobuf/Parser.java
  28. 48 0
      java/src/main/java/com/google/protobuf/ProtocolStringList.java
  29. 14 0
      java/src/main/java/com/google/protobuf/RopeByteString.java
  30. 2 3
      java/src/main/java/com/google/protobuf/RpcUtil.java
  31. 599 186
      java/src/main/java/com/google/protobuf/TextFormat.java
  32. 17 0
      java/src/main/java/com/google/protobuf/UnknownFieldSet.java
  33. 55 2
      java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
  34. 18 0
      java/src/test/java/com/google/protobuf/AbstractMessageTest.java
  35. 67 0
      java/src/test/java/com/google/protobuf/ByteStringTest.java
  36. 141 0
      java/src/test/java/com/google/protobuf/CheckUtf8Test.java
  37. 260 19
      java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
  38. 84 0
      java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
  39. 63 3
      java/src/test/java/com/google/protobuf/DescriptorsTest.java
  40. 46 0
      java/src/test/java/com/google/protobuf/DynamicMessageTest.java
  41. 370 1
      java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  42. 134 0
      java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
  43. 121 0
      java/src/test/java/com/google/protobuf/LazyFieldTest.java
  44. 319 0
      java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
  45. 12 0
      java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
  46. 85 0
      java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
  47. 15 9
      java/src/test/java/com/google/protobuf/ParserTest.java
  48. 33 0
      java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
  49. 172 3
      java/src/test/java/com/google/protobuf/TestUtil.java
  50. 318 7
      java/src/test/java/com/google/protobuf/TextFormatTest.java
  51. 216 0
      java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
  52. 75 0
      java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
  53. 28 2
      java/src/test/java/com/google/protobuf/WireFormatTest.java
  54. 61 0
      java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
  55. 17 25
      java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto
  56. 7 1
      java/src/test/java/com/google/protobuf/multiple_files_test.proto
  57. 1 0
      java/src/test/java/com/google/protobuf/nested_extension.proto
  58. 1 0
      java/src/test/java/com/google/protobuf/non_nested_extension.proto
  59. 38 0
      java/src/test/java/com/google/protobuf/outer_class_name_test.proto
  60. 42 0
      java/src/test/java/com/google/protobuf/outer_class_name_test2.proto
  61. 43 0
      java/src/test/java/com/google/protobuf/outer_class_name_test3.proto
  62. 49 0
      java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
  63. 50 0
      java/src/test/java/com/google/protobuf/test_check_utf8.proto
  64. 51 0
      java/src/test/java/com/google/protobuf/test_check_utf8_size.proto
  65. 43 0
      java/src/test/java/com/google/protobuf/test_custom_options.proto
  66. 22 49
      java/src/test/java/com/google/protobuf/test_extra_interfaces.proto
  67. 0 1717
      python/google/protobuf/pyext/python-proto2.cc
  68. 0 337
      python/google/protobuf/pyext/python_descriptor.cc
  69. 37 1
      python/setup.py
  70. 20 4
      src/Makefile.am
  71. 6 2
      src/google/protobuf/compiler/code_generator.cc
  72. 3 0
      src/google/protobuf/compiler/code_generator.h
  73. 180 14
      src/google/protobuf/compiler/command_line_interface.cc
  74. 27 2
      src/google/protobuf/compiler/command_line_interface.h
  75. 104 23
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  76. 4 4
      src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
  77. 41 11
      src/google/protobuf/compiler/cpp/cpp_enum.cc
  78. 2 0
      src/google/protobuf/compiler/cpp/cpp_enum.h
  79. 69 4
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc
  80. 18 1
      src/google/protobuf/compiler/cpp/cpp_enum_field.h
  81. 26 2
      src/google/protobuf/compiler/cpp/cpp_field.cc
  82. 9 1
      src/google/protobuf/compiler/cpp/cpp_field.h
  83. 37 24
      src/google/protobuf/compiler/cpp/cpp_file.cc
  84. 1 1
      src/google/protobuf/compiler/cpp/cpp_file.h
  85. 3 2
      src/google/protobuf/compiler/cpp/cpp_generator.cc
  86. 88 32
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  87. 22 2
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  88. 599 112
      src/google/protobuf/compiler/cpp/cpp_message.cc
  89. 5 1
      src/google/protobuf/compiler/cpp/cpp_message.h
  90. 80 3
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  91. 18 1
      src/google/protobuf/compiler/cpp/cpp_message_field.h
  92. 10 8
      src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
  93. 64 0
      src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
  94. 19 1
      src/google/protobuf/compiler/cpp/cpp_primitive_field.h
  95. 0 1
      src/google/protobuf/compiler/cpp/cpp_service.h
  96. 167 16
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  97. 20 1
      src/google/protobuf/compiler/cpp/cpp_string_field.h
  98. 9 0
      src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
  99. 726 6
      src/google/protobuf/compiler/cpp/cpp_unittest.cc
  100. 30 9
      src/google/protobuf/compiler/importer.cc

+ 17 - 5
Makefile.am

@@ -78,6 +78,7 @@ EXTRA_DIST =                                                                 \
   java/src/main/java/com/google/protobuf/CodedOutputStream.java              \
   java/src/main/java/com/google/protobuf/Descriptors.java                    \
   java/src/main/java/com/google/protobuf/DynamicMessage.java                 \
+  java/src/main/java/com/google/protobuf/Extension.java                      \
   java/src/main/java/com/google/protobuf/ExtensionRegistry.java              \
   java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java          \
   java/src/main/java/com/google/protobuf/FieldSet.java                       \
@@ -86,6 +87,7 @@ EXTRA_DIST =                                                                 \
   java/src/main/java/com/google/protobuf/Internal.java                       \
   java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
   java/src/main/java/com/google/protobuf/LazyField.java                      \
+  java/src/main/java/com/google/protobuf/LazyFieldLite.java                  \
   java/src/main/java/com/google/protobuf/LazyStringArrayList.java            \
   java/src/main/java/com/google/protobuf/LazyStringList.java                 \
   java/src/main/java/com/google/protobuf/LiteralByteString.java              \
@@ -93,8 +95,10 @@ EXTRA_DIST =                                                                 \
   java/src/main/java/com/google/protobuf/MessageLite.java                    \
   java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java           \
   java/src/main/java/com/google/protobuf/MessageOrBuilder.java               \
+  java/src/main/java/com/google/protobuf/MessageReflection.java              \
   java/src/main/java/com/google/protobuf/Parser.java                         \
   java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java            \
+  java/src/main/java/com/google/protobuf/ProtocolStringList.java             \
   java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java           \
   java/src/main/java/com/google/protobuf/RopeByteString.java                 \
   java/src/main/java/com/google/protobuf/RpcCallback.java                    \
@@ -114,6 +118,7 @@ EXTRA_DIST =                                                                 \
   java/src/test/java/com/google/protobuf/AbstractMessageTest.java            \
   java/src/test/java/com/google/protobuf/BoundedByteStringTest.java          \
   java/src/test/java/com/google/protobuf/ByteStringTest.java                 \
+  java/src/test/java/com/google/protobuf/CheckUtf8Test.java                  \
   java/src/test/java/com/google/protobuf/CodedInputStreamTest.java           \
   java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java          \
   java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java            \
@@ -123,8 +128,12 @@ EXTRA_DIST =                                                                 \
   java/src/test/java/com/google/protobuf/GeneratedMessageTest.java           \
   java/src/test/java/com/google/protobuf/IsValidUtf8Test.java                \
   java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java            \
+  java/src/test/java/com/google/protobuf/LazyFieldTest.java                  \
+  java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java              \
+  java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java            \
   java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java        \
   java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java         \
+  java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java          \
   java/src/test/java/com/google/protobuf/LiteralByteStringTest.java          \
   java/src/test/java/com/google/protobuf/LiteTest.java                       \
   java/src/test/java/com/google/protobuf/MessageTest.java                    \
@@ -142,13 +151,21 @@ EXTRA_DIST =                                                                 \
   java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java            \
   java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java \
   java/src/test/java/com/google/protobuf/WireFormatTest.java                 \
+  java/src/test/java/com/google/protobuf/lazy_fields_lite.proto              \
+  java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto          \
   java/src/test/java/com/google/protobuf/multiple_files_test.proto           \
   java/src/test/java/com/google/protobuf/nested_builders_test.proto          \
   java/src/test/java/com/google/protobuf/nested_extension_lite.proto         \
   java/src/test/java/com/google/protobuf/nested_extension.proto              \
   java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto     \
   java/src/test/java/com/google/protobuf/non_nested_extension.proto          \
+  java/src/test/java/com/google/protobuf/outer_class_name_test.proto         \
+  java/src/test/java/com/google/protobuf/outer_class_name_test2.proto        \
+  java/src/test/java/com/google/protobuf/outer_class_name_test3.proto        \
   java/src/test/java/com/google/protobuf/test_bad_identifiers.proto          \
+  java/src/test/java/com/google/protobuf/test_check_utf8.proto               \
+  java/src/test/java/com/google/protobuf/test_check_utf8_size.proto          \
+  java/src/test/java/com/google/protobuf/test_custom_options.proto           \
   java/pom.xml                                                               \
   java/README.txt                                                            \
   python/google/protobuf/internal/generator_test.py                          \
@@ -182,11 +199,6 @@ EXTRA_DIST =                                                                 \
   python/google/protobuf/internal/wire_format.py                             \
   python/google/protobuf/internal/wire_format_test.py                        \
   python/google/protobuf/internal/__init__.py                                \
-  python/google/protobuf/pyext/python-proto2.cc                              \
-  python/google/protobuf/pyext/python_descriptor.cc                          \
-  python/google/protobuf/pyext/python_descriptor.h                           \
-  python/google/protobuf/pyext/python_protobuf.cc                            \
-  python/google/protobuf/pyext/python_protobuf.h                             \
   python/google/protobuf/descriptor.py                                       \
   python/google/protobuf/descriptor_database.py                              \
   python/google/protobuf/descriptor_pool.py                                  \

+ 1 - 1
examples/Makefile

@@ -30,7 +30,7 @@ list_people_cpp: list_people.cc protoc_middleman
 	c++ list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs protobuf`
 
 javac_middleman: AddPerson.java ListPeople.java protoc_middleman
-	javac AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
+	javac AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java com/example/tutorial/AddressBookProtosInternalDescriptors.java
 	@touch javac_middleman
 
 add_person_java: javac_middleman

+ 10 - 0
java/pom.xml

@@ -104,6 +104,8 @@
                   <arg value="../src/google/protobuf/unittest_import.proto" />
                   <arg value="../src/google/protobuf/unittest_import_public.proto" />
                   <arg value="../src/google/protobuf/unittest_mset.proto" />
+                  <arg value="src/test/java/com/google/protobuf/lazy_fields_lite.proto" />
+                  <arg value="src/test/java/com/google/protobuf/lite_equals_and_hash.proto" />
                   <arg
                     value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
                   <arg value="src/test/java/com/google/protobuf/nested_builders_test.proto" />
@@ -111,7 +113,13 @@
                   <arg value="src/test/java/com/google/protobuf/nested_extension_lite.proto" />
                   <arg value="src/test/java/com/google/protobuf/non_nested_extension.proto" />
                   <arg value="src/test/java/com/google/protobuf/non_nested_extension_lite.proto" />
+                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test.proto" />
+                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test2.proto" />
+                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test3.proto" />
                   <arg value="src/test/java/com/google/protobuf/test_bad_identifiers.proto" />
+                  <arg value="src/test/java/com/google/protobuf/test_check_utf8.proto" />
+                  <arg value="src/test/java/com/google/protobuf/test_check_utf8_size.proto" />
+                  <arg value="src/test/java/com/google/protobuf/test_custom_options.proto" />
                   <arg
                     value="../src/google/protobuf/unittest_optimize_for.proto" />
                   <arg
@@ -179,6 +187,8 @@
                 <include>**/RopeByteString.java</include>
                 <include>**/Utf8.java</include>
                 <include>**/LazyField.java</include>
+                <include>**/LazyFieldLite.java</include>
+                <include>**/ProtocolStringList.java</include>
               </includes>
               <testIncludes>
                 <testInclude>**/LiteTest.java</testInclude>

+ 133 - 597
java/src/main/java/com/google/protobuf/AbstractMessage.java

@@ -30,14 +30,13 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.GeneratedMessage.ExtendableBuilder;
+import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.Internal.EnumLite;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -49,56 +48,30 @@ import java.util.Map;
  */
 public abstract class AbstractMessage extends AbstractMessageLite
                                       implements Message {
-  @SuppressWarnings("unchecked")
   public boolean isInitialized() {
-    // Check that all required fields are present.
-    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
-      if (field.isRequired()) {
-        if (!hasField(field)) {
-          return false;
-        }
-      }
-    }
-
-    // Check that embedded messages are initialized.
-    for (final Map.Entry<FieldDescriptor, Object> entry :
-        getAllFields().entrySet()) {
-      final FieldDescriptor field = entry.getKey();
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        if (field.isRepeated()) {
-          for (final Message element : (List<Message>) entry.getValue()) {
-            if (!element.isInitialized()) {
-              return false;
-            }
-          }
-        } else {
-          if (!((Message) entry.getValue()).isInitialized()) {
-            return false;
-          }
-        }
-      }
-    }
-
-    return true;
+    return MessageReflection.isInitialized(this);
   }
 
+
   public List<String> findInitializationErrors() {
-    return Builder.findMissingFields(this);
+    return MessageReflection.findMissingFields(this);
   }
 
   public String getInitializationErrorString() {
-    return delimitWithCommas(findInitializationErrors());
+    return MessageReflection.delimitWithCommas(findInitializationErrors());
   }
 
-  private static String delimitWithCommas(List<String> parts) {
-    StringBuilder result = new StringBuilder();
-    for (String part : parts) {
-      if (result.length() > 0) {
-        result.append(", ");
-      }
-      result.append(part);
-    }
-    return result.toString();
+  /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+  @Override
+  public boolean hasOneof(OneofDescriptor oneof) {
+    throw new UnsupportedOperationException("hasOneof() is not implemented.");
+  }
+
+  /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+  @Override
+  public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+    throw new UnsupportedOperationException(
+        "getOneofFieldDescriptor() is not implemented.");
   }
 
   @Override
@@ -107,28 +80,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
   }
 
   public void writeTo(final CodedOutputStream output) throws IOException {
-    final boolean isMessageSet =
-        getDescriptorForType().getOptions().getMessageSetWireFormat();
-
-    for (final Map.Entry<FieldDescriptor, Object> entry :
-        getAllFields().entrySet()) {
-      final FieldDescriptor field = entry.getKey();
-      final Object value = entry.getValue();
-      if (isMessageSet && field.isExtension() &&
-          field.getType() == FieldDescriptor.Type.MESSAGE &&
-          !field.isRepeated()) {
-        output.writeMessageSetExtension(field.getNumber(), (Message) value);
-      } else {
-        FieldSet.writeField(field, value, output);
-      }
-    }
-
-    final UnknownFieldSet unknownFields = getUnknownFields();
-    if (isMessageSet) {
-      unknownFields.writeAsMessageSetTo(output);
-    } else {
-      unknownFields.writeTo(output);
-    }
+    MessageReflection.writeMessageTo(this, output, false);
   }
 
   private int memoizedSize = -1;
@@ -139,33 +91,8 @@ public abstract class AbstractMessage extends AbstractMessageLite
       return size;
     }
 
-    size = 0;
-    final boolean isMessageSet =
-        getDescriptorForType().getOptions().getMessageSetWireFormat();
-
-    for (final Map.Entry<FieldDescriptor, Object> entry :
-        getAllFields().entrySet()) {
-      final FieldDescriptor field = entry.getKey();
-      final Object value = entry.getValue();
-      if (isMessageSet && field.isExtension() &&
-          field.getType() == FieldDescriptor.Type.MESSAGE &&
-          !field.isRepeated()) {
-        size += CodedOutputStream.computeMessageSetExtensionSize(
-            field.getNumber(), (Message) value);
-      } else {
-        size += FieldSet.computeFieldSize(field, value);
-      }
-    }
-
-    final UnknownFieldSet unknownFields = getUnknownFields();
-    if (isMessageSet) {
-      size += unknownFields.getSerializedSizeAsMessageSet();
-    } else {
-      size += unknownFields.getSerializedSize();
-    }
-
-    memoizedSize = size;
-    return size;
+    memoizedSize = MessageReflection.getSerializedSize(this);
+    return memoizedSize;
   }
 
   @Override
@@ -180,22 +107,93 @@ public abstract class AbstractMessage extends AbstractMessageLite
     if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
       return false;
     }
-    return getAllFields().equals(otherMessage.getAllFields()) &&
+    return compareFields(getAllFields(), otherMessage.getAllFields()) &&
         getUnknownFields().equals(otherMessage.getUnknownFields());
   }
 
   @Override
   public int hashCode() {
-    int hash = 41;
-    hash = (19 * hash) + getDescriptorForType().hashCode();
-    hash = hashFields(hash, getAllFields());
-    hash = (29 * hash) + getUnknownFields().hashCode();
+    int hash = memoizedHashCode;
+    if (hash == 0) {
+      hash = 41;
+      hash = (19 * hash) + getDescriptorForType().hashCode();
+      hash = hashFields(hash, getAllFields());
+      hash = (29 * hash) + getUnknownFields().hashCode();
+      memoizedHashCode = hash;
+    }
     return hash;
   }
+  
+  private static ByteString toByteString(Object value) {
+    if (value instanceof byte[]) {
+      return ByteString.copyFrom((byte[]) value);
+    } else {
+      return (ByteString) value;
+    }
+  }
+ 
+  /**
+   * Compares two bytes fields. The parameters must be either a byte array or a
+   * ByteString object. They can be of different type though.
+   */
+  private static boolean compareBytes(Object a, Object b) {
+    if (a instanceof byte[] && b instanceof byte[]) {
+      return Arrays.equals((byte[])a, (byte[])b);
+    }
+    return toByteString(a).equals(toByteString(b));
+  }
+  
+  /**
+   * Compares two set of fields.
+   * This method is used to implement {@link AbstractMessage#equals(Object)}
+   * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
+   * of bytes fields because immutable messages and mutable messages use
+   * different Java type to reprensent a bytes field and this method should be
+   * able to compare immutable messages, mutable messages and also an immutable
+   * message to a mutable message.
+   */
+  static boolean compareFields(Map<FieldDescriptor, Object> a,
+      Map<FieldDescriptor, Object> b) {
+    if (a.size() != b.size()) {
+      return false;
+    }
+    for (FieldDescriptor descriptor : a.keySet()) {
+      if (!b.containsKey(descriptor)) {
+        return false;
+      }
+      Object value1 = a.get(descriptor);
+      Object value2 = b.get(descriptor);
+      if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
+        if (descriptor.isRepeated()) {
+          List list1 = (List) value1;
+          List list2 = (List) value2;
+          if (list1.size() != list2.size()) {
+            return false;
+          }
+          for (int i = 0; i < list1.size(); i++) {
+            if (!compareBytes(list1.get(i), list2.get(i))) {
+              return false;
+            }
+          }
+        } else {
+          // Compares a singular bytes field.
+          if (!compareBytes(value1, value2)) {
+            return false;
+          }
+        }
+      } else {
+        // Compare non-bytes fields.
+        if (!value1.equals(value2)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
 
   /** Get a hash code for given fields and values, using the given seed. */
   @SuppressWarnings("unchecked")
-  protected int hashFields(int hash, Map<FieldDescriptor, Object> map) {
+  protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
     for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
       FieldDescriptor field = entry.getKey();
       Object value = entry.getValue();
@@ -204,30 +202,14 @@ public abstract class AbstractMessage extends AbstractMessageLite
         hash = (53 * hash) + value.hashCode();
       } else if (field.isRepeated()) {
         List<? extends EnumLite> list = (List<? extends EnumLite>) value;
-        hash = (53 * hash) + hashEnumList(list);
+        hash = (53 * hash) + Internal.hashEnumList(list);
       } else {
-        hash = (53 * hash) + hashEnum((EnumLite) value);
+        hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
       }
     }
     return hash;
   }
 
-  /**
-   * Helper method for implementing {@link Message#hashCode()}.
-   * @see Boolean#hashCode()
-   */
-  protected static int hashLong(long n) {
-    return (int) (n ^ (n >>> 32));
-  }
-
-  /**
-   * Helper method for implementing {@link Message#hashCode()}.
-   * @see Boolean#hashCode()
-   */
-  protected static int hashBoolean(boolean b) {
-    return b ? 1231 : 1237;
-  }
-
   /**
    * Package private helper method for AbstractParser to create
    * UninitializedMessageException with missing field information.
@@ -237,26 +219,6 @@ public abstract class AbstractMessage extends AbstractMessageLite
     return Builder.newUninitializedMessageException(this);
   }
 
-  /**
-   * Helper method for implementing {@link Message#hashCode()}.
-   * <p>
-   * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
-   * need to use the field number as the hash code to ensure compatibility
-   * between statically and dynamically generated enum objects.
-   */
-  protected static int hashEnum(EnumLite e) {
-    return e.getNumber();
-  }
-
-  /** Helper method for implementing {@link Message#hashCode()}. */
-  protected static int hashEnumList(List<? extends EnumLite> list) {
-    int hash = 1;
-    for (EnumLite e : list) {
-      hash = 31 * hash + hashEnum(e);
-    }
-    return hash;
-  }
-
   // =================================================================
 
   /**
@@ -272,6 +234,25 @@ public abstract class AbstractMessage extends AbstractMessageLite
     @Override
     public abstract BuilderType clone();
 
+    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+    @Override
+    public boolean hasOneof(OneofDescriptor oneof) {
+      throw new UnsupportedOperationException("hasOneof() is not implemented.");
+    }
+
+    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+    @Override
+    public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+      throw new UnsupportedOperationException(
+          "getOneofFieldDescriptor() is not implemented.");
+    }
+
+    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+    @Override
+    public BuilderType clearOneof(OneofDescriptor oneof) {
+      throw new UnsupportedOperationException("clearOneof() is not implemented.");
+    }
+
     public BuilderType clear() {
       for (final Map.Entry<FieldDescriptor, Object> entry :
            getAllFields().entrySet()) {
@@ -281,11 +262,11 @@ public abstract class AbstractMessage extends AbstractMessageLite
     }
 
     public List<String> findInitializationErrors() {
-      return findMissingFields(this);
+      return MessageReflection.findMissingFields(this);
     }
 
     public String getInitializationErrorString() {
-      return delimitWithCommas(findInitializationErrors());
+      return MessageReflection.delimitWithCommas(findInitializationErrors());
     }
 
     public BuilderType mergeFrom(final Message other) {
@@ -350,8 +331,13 @@ public abstract class AbstractMessage extends AbstractMessageLite
           break;
         }
 
-        if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
-                            getDescriptorForType(), this, null, tag)) {
+        MessageReflection.BuilderAdapter builderAdapter =
+            new MessageReflection.BuilderAdapter(this);
+        if (!MessageReflection.mergeFieldFrom(input, unknownFields,
+                                              extensionRegistry,
+                                              getDescriptorForType(),
+                                              builderAdapter,
+                                              tag)) {
           // end group tag
           break;
         }
@@ -360,394 +346,6 @@ public abstract class AbstractMessage extends AbstractMessageLite
       return (BuilderType) this;
     }
 
-    /** helper method to handle {@code builder} and {@code extensions}. */
-    private static void addRepeatedField(
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions,
-        FieldDescriptor field,
-        Object value) {
-      if (builder != null) {
-        builder.addRepeatedField(field, value);
-      } else {
-        extensions.addRepeatedField(field, value);
-      }
-    }
-
-    /** helper method to handle {@code builder} and {@code extensions}. */
-    private static void setField(
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions,
-        FieldDescriptor field,
-        Object value) {
-      if (builder != null) {
-        builder.setField(field, value);
-      } else {
-        extensions.setField(field, value);
-      }
-    }
-
-    /** helper method to handle {@code builder} and {@code extensions}. */
-    private static boolean hasOriginalMessage(
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions,
-        FieldDescriptor field) {
-      if (builder != null) {
-        return builder.hasField(field);
-      } else {
-        return extensions.hasField(field);
-      }
-    }
-
-    /** helper method to handle {@code builder} and {@code extensions}. */
-    private static Message getOriginalMessage(
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions,
-        FieldDescriptor field) {
-      if (builder != null) {
-        return (Message) builder.getField(field);
-      } else {
-        return (Message) extensions.getField(field);
-      }
-    }
-
-    /** helper method to handle {@code builder} and {@code extensions}. */
-    private static void mergeOriginalMessage(
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions,
-        FieldDescriptor field,
-        Message.Builder subBuilder) {
-      Message originalMessage = getOriginalMessage(builder, extensions, field);
-      if (originalMessage != null) {
-        subBuilder.mergeFrom(originalMessage);
-      }
-    }
-
-    /**
-     * Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but
-     * parses a single field.
-     *
-     * When {@code builder} is not null, the method will parse and merge the
-     * field into {@code builder}. Otherwise, it will try to parse the field
-     * into {@code extensions}, when it's called by the parsing constructor in
-     * generated classes.
-     *
-     * Package-private because it is used by GeneratedMessage.ExtendableMessage.
-     * @param tag The tag, which should have already been read.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    static boolean mergeFieldFrom(
-        CodedInputStream input,
-        UnknownFieldSet.Builder unknownFields,
-        ExtensionRegistryLite extensionRegistry,
-        Descriptor type,
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions,
-        int tag) throws IOException {
-      if (type.getOptions().getMessageSetWireFormat() &&
-          tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
-        mergeMessageSetExtensionFromCodedStream(
-            input, unknownFields, extensionRegistry, type, builder, extensions);
-        return true;
-      }
-
-      final int wireType = WireFormat.getTagWireType(tag);
-      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
-      final FieldDescriptor field;
-      Message defaultInstance = null;
-
-      if (type.isExtensionNumber(fieldNumber)) {
-        // extensionRegistry may be either ExtensionRegistry or
-        // ExtensionRegistryLite.  Since the type we are parsing is a full
-        // message, only a full ExtensionRegistry could possibly contain
-        // extensions of it.  Otherwise we will treat the registry as if it
-        // were empty.
-        if (extensionRegistry instanceof ExtensionRegistry) {
-          final ExtensionRegistry.ExtensionInfo extension =
-            ((ExtensionRegistry) extensionRegistry)
-              .findExtensionByNumber(type, fieldNumber);
-          if (extension == null) {
-            field = null;
-          } else {
-            field = extension.descriptor;
-            defaultInstance = extension.defaultInstance;
-            if (defaultInstance == null &&
-                field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-              throw new IllegalStateException(
-                  "Message-typed extension lacked default instance: " +
-                  field.getFullName());
-            }
-          }
-        } else {
-          field = null;
-        }
-      } else if (builder != null) {
-        field = type.findFieldByNumber(fieldNumber);
-      } else {
-        field = null;
-      }
-
-      boolean unknown = false;
-      boolean packed = false;
-      if (field == null) {
-        unknown = true;  // Unknown field.
-      } else if (wireType == FieldSet.getWireFormatForFieldType(
-                   field.getLiteType(),
-                   false  /* isPacked */)) {
-        packed = false;
-      } else if (field.isPackable() &&
-                 wireType == FieldSet.getWireFormatForFieldType(
-                   field.getLiteType(),
-                   true  /* isPacked */)) {
-        packed = true;
-      } else {
-        unknown = true;  // Unknown wire type.
-      }
-
-      if (unknown) {  // Unknown field or wrong wire type.  Skip.
-        return unknownFields.mergeFieldFrom(tag, input);
-      }
-
-      if (packed) {
-        final int length = input.readRawVarint32();
-        final int limit = input.pushLimit(length);
-        if (field.getLiteType() == WireFormat.FieldType.ENUM) {
-          while (input.getBytesUntilLimit() > 0) {
-            final int rawValue = input.readEnum();
-            final Object value = field.getEnumType().findValueByNumber(rawValue);
-            if (value == null) {
-              // If the number isn't recognized as a valid value for this
-              // enum, drop it (don't even add it to unknownFields).
-              return true;
-            }
-            addRepeatedField(builder, extensions, field, value);
-          }
-        } else {
-          while (input.getBytesUntilLimit() > 0) {
-            final Object value =
-              FieldSet.readPrimitiveField(input, field.getLiteType());
-            addRepeatedField(builder, extensions, field, value);
-          }
-        }
-        input.popLimit(limit);
-      } else {
-        final Object value;
-        switch (field.getType()) {
-          case GROUP: {
-            final Message.Builder subBuilder;
-            if (defaultInstance != null) {
-              subBuilder = defaultInstance.newBuilderForType();
-            } else {
-              subBuilder = builder.newBuilderForField(field);
-            }
-            if (!field.isRepeated()) {
-              mergeOriginalMessage(builder, extensions, field, subBuilder);
-            }
-            input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
-            value = subBuilder.buildPartial();
-            break;
-          }
-          case MESSAGE: {
-            final Message.Builder subBuilder;
-            if (defaultInstance != null) {
-              subBuilder = defaultInstance.newBuilderForType();
-            } else {
-              subBuilder = builder.newBuilderForField(field);
-            }
-            if (!field.isRepeated()) {
-              mergeOriginalMessage(builder, extensions, field, subBuilder);
-            }
-            input.readMessage(subBuilder, extensionRegistry);
-            value = subBuilder.buildPartial();
-            break;
-          }
-          case ENUM:
-            final int rawValue = input.readEnum();
-            value = field.getEnumType().findValueByNumber(rawValue);
-            // If the number isn't recognized as a valid value for this enum,
-            // drop it.
-            if (value == null) {
-              unknownFields.mergeVarintField(fieldNumber, rawValue);
-              return true;
-            }
-            break;
-          default:
-            value = FieldSet.readPrimitiveField(input, field.getLiteType());
-            break;
-        }
-
-        if (field.isRepeated()) {
-          addRepeatedField(builder, extensions, field, value);
-        } else {
-          setField(builder, extensions, field, value);
-        }
-      }
-
-      return true;
-    }
-
-    /**
-     * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension.
-     * If {@code builder} is not null, this method will merge MessageSet into
-     * the builder.  Otherwise, it will merge the MessageSet into {@code
-     * extensions}.
-     */
-    private static void mergeMessageSetExtensionFromCodedStream(
-        CodedInputStream input,
-        UnknownFieldSet.Builder unknownFields,
-        ExtensionRegistryLite extensionRegistry,
-        Descriptor type,
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions) throws IOException {
-
-      // The wire format for MessageSet is:
-      //   message MessageSet {
-      //     repeated group Item = 1 {
-      //       required int32 typeId = 2;
-      //       required bytes message = 3;
-      //     }
-      //   }
-      // "typeId" is the extension's field number.  The extension can only be
-      // a message type, where "message" contains the encoded bytes of that
-      // message.
-      //
-      // In practice, we will probably never see a MessageSet item in which
-      // the message appears before the type ID, or where either field does not
-      // appear exactly once.  However, in theory such cases are valid, so we
-      // should be prepared to accept them.
-
-      int typeId = 0;
-      ByteString rawBytes = null; // If we encounter "message" before "typeId"
-      ExtensionRegistry.ExtensionInfo extension = null;
-
-      // Read bytes from input, if we get it's type first then parse it eagerly,
-      // otherwise we store the raw bytes in a local variable.
-      while (true) {
-        final int tag = input.readTag();
-        if (tag == 0) {
-          break;
-        }
-
-        if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
-          typeId = input.readUInt32();
-          if (typeId != 0) {
-            // extensionRegistry may be either ExtensionRegistry or
-            // ExtensionRegistryLite. Since the type we are parsing is a full
-            // message, only a full ExtensionRegistry could possibly contain
-            // extensions of it. Otherwise we will treat the registry as if it
-            // were empty.
-            if (extensionRegistry instanceof ExtensionRegistry) {
-              extension = ((ExtensionRegistry) extensionRegistry)
-                  .findExtensionByNumber(type, typeId);
-            }
-          }
-
-        } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
-          if (typeId != 0) {
-            if (extension != null && ExtensionRegistryLite.isEagerlyParseMessageSets()) {
-              // We already know the type, so we can parse directly from the
-              // input with no copying.  Hooray!
-              eagerlyMergeMessageSetExtension(
-                  input, extension, extensionRegistry, builder, extensions);
-              rawBytes = null;
-              continue;
-            }
-          }
-          // We haven't seen a type ID yet or we want parse message lazily.
-          rawBytes = input.readBytes();
-
-        } else { // Unknown tag. Skip it.
-          if (!input.skipField(tag)) {
-            break; // End of group
-          }
-        }
-      }
-      input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
-
-      // Process the raw bytes.
-      if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
-        if (extension != null) { // We known the type
-          mergeMessageSetExtensionFromBytes(
-              rawBytes, extension, extensionRegistry, builder, extensions);
-        } else { // We don't know how to parse this. Ignore it.
-          if (rawBytes != null) {
-            unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
-                .addLengthDelimited(rawBytes).build());
-          }
-        }
-      }
-    }
-
-    private static void eagerlyMergeMessageSetExtension(
-        CodedInputStream input,
-        ExtensionRegistry.ExtensionInfo extension,
-        ExtensionRegistryLite extensionRegistry,
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions) throws IOException {
-
-      FieldDescriptor field = extension.descriptor;
-      Message value = null;
-      if (hasOriginalMessage(builder, extensions, field)) {
-        Message originalMessage =
-            getOriginalMessage(builder, extensions, field);
-        Message.Builder subBuilder = originalMessage.toBuilder();
-        input.readMessage(subBuilder, extensionRegistry);
-        value = subBuilder.buildPartial();
-      } else {
-        value = input.readMessage(extension.defaultInstance.getParserForType(),
-          extensionRegistry);
-      }
-
-      if (builder != null) {
-        builder.setField(field, value);
-      } else {
-        extensions.setField(field, value);
-      }
-    }
-
-    private static void mergeMessageSetExtensionFromBytes(
-        ByteString rawBytes,
-        ExtensionRegistry.ExtensionInfo extension,
-        ExtensionRegistryLite extensionRegistry,
-        Message.Builder builder,
-        FieldSet<FieldDescriptor> extensions) throws IOException {
-
-      FieldDescriptor field = extension.descriptor;
-      boolean hasOriginalValue = hasOriginalMessage(builder, extensions, field);
-
-      if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
-        // If the field already exists, we just parse the field.
-        Message value = null;
-        if (hasOriginalValue) {
-          Message originalMessage =
-              getOriginalMessage(builder, extensions, field);
-          Message.Builder subBuilder= originalMessage.toBuilder();
-          subBuilder.mergeFrom(rawBytes, extensionRegistry);
-          value = subBuilder.buildPartial();
-        } else {
-          value = extension.defaultInstance.getParserForType()
-              .parsePartialFrom(rawBytes, extensionRegistry);
-        }
-        setField(builder, extensions, field, value);
-      } else {
-        // Use LazyField to load MessageSet lazily.
-        LazyField lazyField = new LazyField(
-            extension.defaultInstance, extensionRegistry, rawBytes);
-        if (builder != null) {
-          // TODO(xiangl): it looks like this method can only be invoked by
-          // ExtendableBuilder, but I'm not sure. So I double check the type of
-          // builder here. It may be useless and need more investigation.
-          if (builder instanceof ExtendableBuilder) {
-            builder.setField(field, lazyField);
-          } else {
-            builder.setField(field, lazyField.getValue());
-          }
-        } else {
-          extensions.setField(field, lazyField);
-        }
-      }
-    }
-
     public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
       setUnknownFields(
         UnknownFieldSet.newBuilder(getUnknownFields())
@@ -761,79 +359,18 @@ public abstract class AbstractMessage extends AbstractMessageLite
           "getFieldBuilder() called on an unsupported message type.");
     }
 
+    public String toString() {
+      return TextFormat.printToString(this);
+    }
+
     /**
      * Construct an UninitializedMessageException reporting missing fields in
      * the given message.
      */
     protected static UninitializedMessageException
         newUninitializedMessageException(Message message) {
-      return new UninitializedMessageException(findMissingFields(message));
-    }
-
-    /**
-     * Populates {@code this.missingFields} with the full "path" of each
-     * missing required field in the given message.
-     */
-    private static List<String> findMissingFields(
-        final MessageOrBuilder message) {
-      final List<String> results = new ArrayList<String>();
-      findMissingFields(message, "", results);
-      return results;
-    }
-
-    /** Recursive helper implementing {@link #findMissingFields(Message)}. */
-    private static void findMissingFields(final MessageOrBuilder message,
-                                          final String prefix,
-                                          final List<String> results) {
-      for (final FieldDescriptor field :
-          message.getDescriptorForType().getFields()) {
-        if (field.isRequired() && !message.hasField(field)) {
-          results.add(prefix + field.getName());
-        }
-      }
-
-      for (final Map.Entry<FieldDescriptor, Object> entry :
-           message.getAllFields().entrySet()) {
-        final FieldDescriptor field = entry.getKey();
-        final Object value = entry.getValue();
-
-        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-          if (field.isRepeated()) {
-            int i = 0;
-            for (final Object element : (List) value) {
-              findMissingFields((MessageOrBuilder) element,
-                                subMessagePrefix(prefix, field, i++),
-                                results);
-            }
-          } else {
-            if (message.hasField(field)) {
-              findMissingFields((MessageOrBuilder) value,
-                                subMessagePrefix(prefix, field, -1),
-                                results);
-            }
-          }
-        }
-      }
-    }
-
-    private static String subMessagePrefix(final String prefix,
-                                           final FieldDescriptor field,
-                                           final int index) {
-      final StringBuilder result = new StringBuilder(prefix);
-      if (field.isExtension()) {
-        result.append('(')
-              .append(field.getFullName())
-              .append(')');
-      } else {
-        result.append(field.getName());
-      }
-      if (index != -1) {
-        result.append('[')
-              .append(index)
-              .append(']');
-      }
-      result.append('.');
-      return result.toString();
+      return new UninitializedMessageException(
+          MessageReflection.findMissingFields(message));
     }
 
     // ===============================================================
@@ -925,6 +462,5 @@ public abstract class AbstractMessage extends AbstractMessageLite
         throws IOException {
       return super.mergeDelimitedFrom(input, extensionRegistry);
     }
-
   }
 }

+ 18 - 6
java/src/main/java/com/google/protobuf/AbstractMessageLite.java

@@ -44,6 +44,8 @@ import java.util.Collection;
  * @author kenton@google.com Kenton Varda
  */
 public abstract class AbstractMessageLite implements MessageLite {
+  protected int memoizedHashCode = 0;
+
   public ByteString toByteString() {
     try {
       final ByteString.CodedBuilder out =
@@ -91,6 +93,7 @@ public abstract class AbstractMessageLite implements MessageLite {
     codedOutput.flush();
   }
 
+
   /**
    * Package private helper method for AbstractParser to create
    * UninitializedMessageException.
@@ -99,6 +102,13 @@ public abstract class AbstractMessageLite implements MessageLite {
     return new UninitializedMessageException(this);
   }
 
+  protected static void checkByteStringIsUtf8(ByteString byteString)
+      throws IllegalArgumentException {
+    if (!byteString.isValidUtf8()) {
+      throw new IllegalArgumentException("Byte string is not UTF-8.");
+    }
+  }
+
   /**
    * A partial implementation of the {@link Message.Builder} interface which
    * implements as many methods of that interface as possible in terms of
@@ -311,7 +321,8 @@ public abstract class AbstractMessageLite implements MessageLite {
      * used by generated code.  Users should ignore it.
      *
      * @throws NullPointerException if any of the elements of {@code values} is
-     * null.
+     * null. When that happens, some elements of {@code values} may have already
+     * been added to the result {@code list}.
      */
     protected static <T> void addAll(final Iterable<T> values,
                                      final Collection<? super T> list) {
@@ -319,14 +330,15 @@ public abstract class AbstractMessageLite implements MessageLite {
         // For StringOrByteStringLists, check the underlying elements to avoid
         // forcing conversions of ByteStrings to Strings.
         checkForNullValues(((LazyStringList) values).getUnderlyingElements());
-      } else {
+        list.addAll((Collection<T>) values);
+      } else if (values instanceof Collection) {
         checkForNullValues(values);
-      }
-      if (values instanceof Collection) {
-        final Collection<T> collection = (Collection<T>) values;
-        list.addAll(collection);
+        list.addAll((Collection<T>) values);
       } else {
         for (final T value : values) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
           list.add(value);
         }
       }

+ 0 - 8
java/src/main/java/com/google/protobuf/AbstractParser.java

@@ -110,10 +110,6 @@ public abstract class AbstractParser<MessageType extends MessageLite>
       return message;
     } catch (InvalidProtocolBufferException e) {
       throw e;
-    } catch (IOException e) {
-      throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
     }
   }
 
@@ -147,10 +143,6 @@ public abstract class AbstractParser<MessageType extends MessageLite>
       return message;
     } catch (InvalidProtocolBufferException e) {
       throw e;
-    } catch (IOException e) {
-      throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
     }
   }
 

+ 52 - 0
java/src/main/java/com/google/protobuf/ByteString.java

@@ -177,6 +177,20 @@ public abstract class ByteString implements Iterable<Byte> {
            substring(0, prefix.size()).equals(prefix);
   }
 
+  /**
+   * Tests if this bytestring ends with the specified suffix.
+   * Similar to {@link String#endsWith(String)}
+   *
+   * @param suffix the suffix.
+   * @return <code>true</code> if the byte sequence represented by the
+   *         argument is a suffix of the byte sequence represented by
+   *         this string; <code>false</code> otherwise.
+   */
+  public boolean endsWith(ByteString suffix) {
+    return size() >= suffix.size() &&
+        substring(size() - suffix.size()).equals(suffix);
+  }
+
   // =================================================================
   // byte[] -> ByteString
 
@@ -512,6 +526,9 @@ public abstract class ByteString implements Iterable<Byte> {
    */
   public byte[] toByteArray() {
     int size = size();
+    if (size == 0) {
+      return Internal.EMPTY_BYTE_ARRAY;
+    }
     byte[] result = new byte[size];
     copyToInternal(result, 0, 0, size);
     return result;
@@ -525,6 +542,41 @@ public abstract class ByteString implements Iterable<Byte> {
    * @throws IOException  if an I/O error occurs.
    */
   public abstract void writeTo(OutputStream out) throws IOException;
+  
+  /**
+   * Writes a specified part of this byte string to an output stream.
+   *
+   * @param  out  the output stream to which to write the data.
+   * @param  sourceOffset offset within these bytes
+   * @param  numberToWrite number of bytes to write
+   * @throws IOException  if an I/O error occurs.
+   * @throws IndexOutOfBoundsException if an offset or size is negative or too
+   *     large
+   */
+  void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
+      throws IOException {
+    if (sourceOffset < 0) {
+      throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
+    }
+    if (numberToWrite < 0) {
+      throw new IndexOutOfBoundsException("Length < 0: " + numberToWrite);
+    }
+    if (sourceOffset + numberToWrite > size()) {
+      throw new IndexOutOfBoundsException(
+          "Source end offset exceeded: " + (sourceOffset + numberToWrite));
+    }
+    if (numberToWrite > 0) {
+      writeToInternal(out, sourceOffset, numberToWrite);
+    }
+    
+  }
+
+  /**
+   * Internal version of {@link #writeTo(OutputStream,int,int)} that assumes
+   * all error checking has already been done.
+   */
+  abstract void writeToInternal(OutputStream out, int sourceOffset,
+      int numberToWrite) throws IOException;
 
   /**
    * Constructs a read-only {@code java.nio.ByteBuffer} whose content

+ 531 - 140
java/src/main/java/com/google/protobuf/CodedInputStream.java

@@ -30,9 +30,12 @@
 
 package com.google.protobuf;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -88,6 +91,53 @@ public final class CodedInputStream {
     return result;
   }
 
+  /**
+   * Create a new CodedInputStream wrapping the given ByteBuffer. The data
+   * starting from the ByteBuffer's current position to its limit will be read.
+   * The returned CodedInputStream may or may not share the underlying data
+   * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the
+   * CodedInputStream is in use.
+   * Note that the ByteBuffer's position won't be changed by this function.
+   * Concurrent calls with the same ByteBuffer object are safe if no other
+   * thread is trying to alter the ByteBuffer's status.
+   */
+  public static CodedInputStream newInstance(ByteBuffer buf) {
+    if (buf.hasArray()) {
+      return newInstance(buf.array(), buf.arrayOffset() + buf.position(),
+          buf.remaining());
+    } else {
+      ByteBuffer temp = buf.duplicate();
+      byte[] buffer = new byte[temp.remaining()];
+      temp.get(buffer);
+      return newInstance(buffer);
+    }
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping a LiteralByteString.
+   */
+  static CodedInputStream newInstance(LiteralByteString byteString) {
+    CodedInputStream result = new CodedInputStream(byteString);
+    try {
+      // Some uses of CodedInputStream can be more efficient if they know
+      // exactly how many bytes are available.  By pushing the end point of the
+      // buffer as a limit, we allow them to get this information via
+      // getBytesUntilLimit().  Pushing a limit that we know is at the end of
+      // the stream can never hurt, since we can never past that point anyway.
+      result.pushLimit(byteString.size());
+    } catch (InvalidProtocolBufferException ex) {
+      // The only reason pushLimit() might throw an exception here is if len
+      // is negative. Normally pushLimit()'s parameter comes directly off the
+      // wire, so it's important to catch exceptions in case of corrupt or
+      // malicious data. However, in this case, we expect that len is not a
+      // user-supplied value, so we can assume that it being negative indicates
+      // a programming error. Therefore, throwing an unchecked exception is
+      // appropriate.
+      throw new IllegalArgumentException(ex);
+    }
+    return result;
+  }
+
   // -----------------------------------------------------------------
 
   /**
@@ -125,6 +175,10 @@ public final class CodedInputStream {
     }
   }
 
+  public int getLastTag() {
+    return lastTag;
+  }
+
   /**
    * Reads and discards a single field, given its tag value.
    *
@@ -134,10 +188,10 @@ public final class CodedInputStream {
   public boolean skipField(final int tag) throws IOException {
     switch (WireFormat.getTagWireType(tag)) {
       case WireFormat.WIRETYPE_VARINT:
-        readInt32();
+        skipRawVarint();
         return true;
       case WireFormat.WIRETYPE_FIXED64:
-        readRawLittleEndian64();
+        skipRawBytes(8);
         return true;
       case WireFormat.WIRETYPE_LENGTH_DELIMITED:
         skipRawBytes(readRawVarint32());
@@ -151,8 +205,59 @@ public final class CodedInputStream {
       case WireFormat.WIRETYPE_END_GROUP:
         return false;
       case WireFormat.WIRETYPE_FIXED32:
-        readRawLittleEndian32();
+        skipRawBytes(4);
+        return true;
+      default:
+        throw InvalidProtocolBufferException.invalidWireType();
+    }
+  }
+
+  /**
+   * Reads a single field and writes it to output in wire format,
+   * given its tag value.
+   *
+   * @return {@code false} if the tag is an endgroup tag, in which case
+   *         nothing is skipped.  Otherwise, returns {@code true}.
+   */
+  public boolean skipField(final int tag, final CodedOutputStream output)
+      throws IOException {
+    switch (WireFormat.getTagWireType(tag)) {
+      case WireFormat.WIRETYPE_VARINT: {
+        long value = readInt64();
+        output.writeRawVarint32(tag);
+        output.writeUInt64NoTag(value);
+        return true;
+      }
+      case WireFormat.WIRETYPE_FIXED64: {
+        long value = readRawLittleEndian64();
+        output.writeRawVarint32(tag);
+        output.writeFixed64NoTag(value);
+        return true;
+      }
+      case WireFormat.WIRETYPE_LENGTH_DELIMITED: {
+        ByteString value = readBytes();
+        output.writeRawVarint32(tag);
+        output.writeBytesNoTag(value);
+        return true;
+      }
+      case WireFormat.WIRETYPE_START_GROUP: {
+        output.writeRawVarint32(tag);
+        skipMessage(output);
+        int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
+                                        WireFormat.WIRETYPE_END_GROUP);
+        checkLastTagWas(endtag);
+        output.writeRawVarint32(endtag);
         return true;
+      }
+      case WireFormat.WIRETYPE_END_GROUP: {
+        return false;
+      }
+      case WireFormat.WIRETYPE_FIXED32: {
+        int value = readRawLittleEndian32();
+        output.writeRawVarint32(tag);
+        output.writeFixed32NoTag(value);
+        return true;
+      }
       default:
         throw InvalidProtocolBufferException.invalidWireType();
     }
@@ -171,6 +276,51 @@ public final class CodedInputStream {
     }
   }
 
+  /**
+   * Reads an entire message and writes it to output in wire format.
+   * This will read either until EOF or until an endgroup tag,
+   * whichever comes first.
+   */
+  public void skipMessage(CodedOutputStream output) throws IOException {
+    while (true) {
+      final int tag = readTag();
+      if (tag == 0 || !skipField(tag, output)) {
+        return;
+      }
+    }
+  }
+
+  /**
+   * Collects the bytes skipped and returns the data in a ByteBuffer.
+   */
+  private class SkippedDataSink implements RefillCallback {
+    private int lastPos = bufferPos;
+    private ByteArrayOutputStream byteArrayStream;
+
+    @Override
+    public void onRefill() {
+      if (byteArrayStream == null) {
+        byteArrayStream = new ByteArrayOutputStream();
+      }
+      byteArrayStream.write(buffer, lastPos, bufferPos - lastPos);
+      lastPos = 0;
+    }
+
+    /**
+     * Gets skipped data in a ByteBuffer. This method should only be
+     * called once.
+     */
+    ByteBuffer getSkippedData() {
+      if (byteArrayStream == null) {
+        return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos);
+      } else {
+        byteArrayStream.write(buffer, lastPos, bufferPos);
+        return ByteBuffer.wrap(byteArrayStream.toByteArray());
+      }
+    }
+  }
+
+
   // -----------------------------------------------------------------
 
   /** Read a {@code double} field value from the stream. */
@@ -210,10 +360,14 @@ public final class CodedInputStream {
 
   /** Read a {@code bool} field value from the stream. */
   public boolean readBool() throws IOException {
-    return readRawVarint32() != 0;
+    return readRawVarint64() != 0;
   }
 
-  /** Read a {@code string} field value from the stream. */
+  /**
+   * Read a {@code string} field value from the stream.
+   * If the stream contains malformed UTF-8,
+   * replace the offending bytes with the standard UTF-8 replacement character.
+   */
   public String readString() throws IOException {
     final int size = readRawVarint32();
     if (size <= (bufferSize - bufferPos) && size > 0) {
@@ -222,10 +376,40 @@ public final class CodedInputStream {
       final String result = new String(buffer, bufferPos, size, "UTF-8");
       bufferPos += size;
       return result;
+    } else if (size == 0) {
+      return "";
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return new String(readRawBytesSlowPath(size), "UTF-8");
+    }
+  }
+
+  /**
+   * Read a {@code string} field value from the stream.
+   * If the stream contains malformed UTF-8,
+   * throw exception {@link InvalidProtocolBufferException}.
+   */
+  public String readStringRequireUtf8() throws IOException {
+    final int size = readRawVarint32();
+    final byte[] bytes;
+    int pos = bufferPos;
+    if (size <= (bufferSize - pos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      bytes = buffer;
+      bufferPos = pos + size;
+    } else if (size == 0) {
+      return "";
     } else {
       // Slow path:  Build a byte array first then copy it.
-      return new String(readRawBytes(size), "UTF-8");
+      bytes = readRawBytesSlowPath(size);
+      pos = 0;
     }
+    // TODO(martinrb): We could save a pass by validating while decoding.
+    if (!Utf8.isValidUtf8(bytes, pos, pos + size)) {
+      throw InvalidProtocolBufferException.invalidUtf8();
+    }
+    return new String(bytes, pos, size, "UTF-8");
   }
 
   /** Read a {@code group} field value from the stream. */
@@ -243,6 +427,7 @@ public final class CodedInputStream {
     --recursionDepth;
   }
 
+
   /** Read a {@code group} field value from the stream. */
   public <T extends MessageLite> T readGroup(
       final int fieldNumber,
@@ -295,6 +480,7 @@ public final class CodedInputStream {
     popLimit(oldLimit);
   }
 
+
   /** Read an embedded message field value from the stream. */
   public <T extends MessageLite> T readMessage(
       final Parser<T> parser,
@@ -316,17 +502,58 @@ public final class CodedInputStream {
   /** Read a {@code bytes} field value from the stream. */
   public ByteString readBytes() throws IOException {
     final int size = readRawVarint32();
-    if (size == 0) {
-      return ByteString.EMPTY;
-    } else if (size <= (bufferSize - bufferPos) && size > 0) {
+    if (size <= (bufferSize - bufferPos) && size > 0) {
       // Fast path:  We already have the bytes in a contiguous buffer, so
       //   just copy directly from it.
-      final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
+      final ByteString result = bufferIsImmutable && enableAliasing
+          ? new BoundedByteString(buffer, bufferPos, size)
+          : ByteString.copyFrom(buffer, bufferPos, size);
       bufferPos += size;
       return result;
+    } else if (size == 0) {
+      return ByteString.EMPTY;
     } else {
       // Slow path:  Build a byte array first then copy it.
-      return ByteString.copyFrom(readRawBytes(size));
+      return new LiteralByteString(readRawBytesSlowPath(size));
+    }
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public byte[] readByteArray() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path: We already have the bytes in a contiguous buffer, so
+      // just copy directly from it.
+      final byte[] result =
+          Arrays.copyOfRange(buffer, bufferPos, bufferPos + size);
+      bufferPos += size;
+      return result;
+    } else {
+      // Slow path: Build a byte array first then copy it.
+      return readRawBytesSlowPath(size);
+    }
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public ByteBuffer readByteBuffer() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path: We already have the bytes in a contiguous buffer.
+      // When aliasing is enabled, we can return a ByteBuffer pointing directly
+      // into the underlying byte array without copy if the CodedInputStream is
+      // constructed from a byte array. If aliasing is disabled or the input is
+      // from an InputStream or ByteString, we have to make a copy of the bytes.
+      ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing
+          ? ByteBuffer.wrap(buffer, bufferPos, size).slice()
+          : ByteBuffer.wrap(Arrays.copyOfRange(
+              buffer, bufferPos, bufferPos + size));
+      bufferPos += size;
+      return result;
+    } else if (size == 0) {
+      return Internal.EMPTY_BYTE_BUFFER;
+    } else {
+      // Slow path: Build a byte array first then copy it.
+      return ByteBuffer.wrap(readRawBytesSlowPath(size));
     }
   }
 
@@ -370,37 +597,67 @@ public final class CodedInputStream {
    * upper bits.
    */
   public int readRawVarint32() throws IOException {
-    byte tmp = readRawByte();
-    if (tmp >= 0) {
-      return tmp;
-    }
-    int result = tmp & 0x7f;
-    if ((tmp = readRawByte()) >= 0) {
-      result |= tmp << 7;
-    } else {
-      result |= (tmp & 0x7f) << 7;
-      if ((tmp = readRawByte()) >= 0) {
-        result |= tmp << 14;
+    // See implementation notes for readRawVarint64
+ fastpath: {
+      int pos = bufferPos;
+
+      if (bufferSize == pos) {
+        break fastpath;
+      }
+
+      final byte[] buffer = this.buffer;
+      int x;
+      if ((x = buffer[pos++]) >= 0) {
+        bufferPos = pos;
+        return x;
+      } else if (bufferSize - pos < 9) {
+        break fastpath;
+      } else if ((x ^= (buffer[pos++] << 7)) < 0L) {
+        x ^= (~0L << 7);
+      } else if ((x ^= (buffer[pos++] << 14)) >= 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14);
+      } else if ((x ^= (buffer[pos++] << 21)) < 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21);
       } else {
-        result |= (tmp & 0x7f) << 14;
-        if ((tmp = readRawByte()) >= 0) {
-          result |= tmp << 21;
-        } else {
-          result |= (tmp & 0x7f) << 21;
-          result |= (tmp = readRawByte()) << 28;
-          if (tmp < 0) {
-            // Discard upper 32 bits.
-            for (int i = 0; i < 5; i++) {
-              if (readRawByte() >= 0) {
-                return result;
-              }
-            }
-            throw InvalidProtocolBufferException.malformedVarint();
-          }
+        int y = buffer[pos++];
+        x ^= y << 28;
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+        if (y < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0) {
+          break fastpath;  // Will throw malformedVarint()
         }
       }
+      bufferPos = pos;
+      return x;
     }
-    return result;
+    return (int) readRawVarint64SlowPath();
+  }
+
+  private void skipRawVarint() throws IOException {
+    if (bufferSize - bufferPos >= 10) {
+      final byte[] buffer = this.buffer;
+      int pos = bufferPos;
+      for (int i = 0; i < 10; i++) {
+        if (buffer[pos++] >= 0) {
+          bufferPos = pos;
+          return;
+        }
+      }
+    }
+    skipRawVarintSlowPath();
+  }
+
+  private void skipRawVarintSlowPath() throws IOException {
+    for (int i = 0; i < 10; i++) {
+      if (readRawByte() >= 0) {
+        return;
+      }
+    }
+    throw InvalidProtocolBufferException.malformedVarint();
   }
 
   /**
@@ -456,49 +713,115 @@ public final class CodedInputStream {
 
   /** Read a raw Varint from the stream. */
   public long readRawVarint64() throws IOException {
-    int shift = 0;
+    // Implementation notes:
+    //
+    // Optimized for one-byte values, expected to be common.
+    // The particular code below was selected from various candidates
+    // empirically, by winning VarintBenchmark.
+    //
+    // Sign extension of (signed) Java bytes is usually a nuisance, but
+    // we exploit it here to more easily obtain the sign of bytes read.
+    // Instead of cleaning up the sign extension bits by masking eagerly,
+    // we delay until we find the final (positive) byte, when we clear all
+    // accumulated bits with one xor.  We depend on javac to constant fold.
+ fastpath: {
+      int pos = bufferPos;
+
+      if (bufferSize == pos) {
+        break fastpath;
+      }
+
+      final byte[] buffer = this.buffer;
+      long x;
+      int y;
+      if ((y = buffer[pos++]) >= 0) {
+        bufferPos = pos;
+        return y;
+      } else if (bufferSize - pos < 9) {
+        break fastpath;
+      } else if ((x = y ^ (buffer[pos++] << 7)) < 0L) {
+        x ^= (~0L << 7);
+      } else if ((x ^= (buffer[pos++] << 14)) >= 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14);
+      } else if ((x ^= (buffer[pos++] << 21)) < 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21);
+      } else if ((x ^= ((long) buffer[pos++] << 28)) >= 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+      } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+      } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+      } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
+            ^ (~0L << 49);
+      } else {
+        x ^= ((long) buffer[pos++] << 56);
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
+            ^ (~0L << 49) ^ (~0L << 56);
+        if (x < 0L) {
+          if (buffer[pos++] < 0L) {
+            break fastpath;  // Will throw malformedVarint()
+          }
+        }
+      }
+      bufferPos = pos;
+      return x;
+    }
+    return readRawVarint64SlowPath();
+  }
+
+  /** Variant of readRawVarint64 for when uncomfortably close to the limit. */
+  /* Visible for testing */
+  long readRawVarint64SlowPath() throws IOException {
     long result = 0;
-    while (shift < 64) {
+    for (int shift = 0; shift < 64; shift += 7) {
       final byte b = readRawByte();
-      result |= (long)(b & 0x7F) << shift;
+      result |= (long) (b & 0x7F) << shift;
       if ((b & 0x80) == 0) {
         return result;
       }
-      shift += 7;
     }
     throw InvalidProtocolBufferException.malformedVarint();
   }
 
   /** Read a 32-bit little-endian integer from the stream. */
   public int readRawLittleEndian32() throws IOException {
-    final byte b1 = readRawByte();
-    final byte b2 = readRawByte();
-    final byte b3 = readRawByte();
-    final byte b4 = readRawByte();
-    return (((int)b1 & 0xff)      ) |
-           (((int)b2 & 0xff) <<  8) |
-           (((int)b3 & 0xff) << 16) |
-           (((int)b4 & 0xff) << 24);
+    int pos = bufferPos;
+
+    // hand-inlined ensureAvailable(4);
+    if (bufferSize - pos < 4) {
+      refillBuffer(4);
+      pos = bufferPos;
+    }
+
+    final byte[] buffer = this.buffer;
+    bufferPos = pos + 4;
+    return (((buffer[pos]     & 0xff))       |
+            ((buffer[pos + 1] & 0xff) <<  8) |
+            ((buffer[pos + 2] & 0xff) << 16) |
+            ((buffer[pos + 3] & 0xff) << 24));
   }
 
   /** Read a 64-bit little-endian integer from the stream. */
   public long readRawLittleEndian64() throws IOException {
-    final byte b1 = readRawByte();
-    final byte b2 = readRawByte();
-    final byte b3 = readRawByte();
-    final byte b4 = readRawByte();
-    final byte b5 = readRawByte();
-    final byte b6 = readRawByte();
-    final byte b7 = readRawByte();
-    final byte b8 = readRawByte();
-    return (((long)b1 & 0xff)      ) |
-           (((long)b2 & 0xff) <<  8) |
-           (((long)b3 & 0xff) << 16) |
-           (((long)b4 & 0xff) << 24) |
-           (((long)b5 & 0xff) << 32) |
-           (((long)b6 & 0xff) << 40) |
-           (((long)b7 & 0xff) << 48) |
-           (((long)b8 & 0xff) << 56);
+    int pos = bufferPos;
+
+    // hand-inlined ensureAvailable(8);
+    if (bufferSize - pos < 8) {
+      refillBuffer(8);
+      pos = bufferPos;
+    }
+
+    final byte[] buffer = this.buffer;
+    bufferPos = pos + 8;
+    return ((((long) buffer[pos]     & 0xffL))       |
+            (((long) buffer[pos + 1] & 0xffL) <<  8) |
+            (((long) buffer[pos + 2] & 0xffL) << 16) |
+            (((long) buffer[pos + 3] & 0xffL) << 24) |
+            (((long) buffer[pos + 4] & 0xffL) << 32) |
+            (((long) buffer[pos + 5] & 0xffL) << 40) |
+            (((long) buffer[pos + 6] & 0xffL) << 48) |
+            (((long) buffer[pos + 7] & 0xffL) << 56));
   }
 
   /**
@@ -532,11 +855,13 @@ public final class CodedInputStream {
   // -----------------------------------------------------------------
 
   private final byte[] buffer;
+  private final boolean bufferIsImmutable;
   private int bufferSize;
   private int bufferSizeAfterLimit;
   private int bufferPos;
   private final InputStream input;
   private int lastTag;
+  private boolean enableAliasing = false;
 
   /**
    * The total number of bytes read before the current buffer.  The total
@@ -567,6 +892,7 @@ public final class CodedInputStream {
     bufferPos = off;
     totalBytesRetired = -off;
     input = null;
+    bufferIsImmutable = false;
   }
 
   private CodedInputStream(final InputStream input) {
@@ -575,6 +901,20 @@ public final class CodedInputStream {
     bufferPos = 0;
     totalBytesRetired = 0;
     this.input = input;
+    bufferIsImmutable = false;
+  }
+
+  private CodedInputStream(final LiteralByteString byteString) {
+    buffer = byteString.bytes;
+    bufferPos = byteString.getOffsetIntoBytes();
+    bufferSize = bufferPos + byteString.size();
+    totalBytesRetired = -bufferPos;
+    input = null;
+    bufferIsImmutable = true;
+  }
+
+  public void enableAliasing(boolean enabled) {
+    this.enableAliasing = enabled;
   }
 
   /**
@@ -698,7 +1038,7 @@ public final class CodedInputStream {
    * if the stream has reached a limit created using {@link #pushLimit(int)}.
    */
   public boolean isAtEnd() throws IOException {
-    return bufferPos == bufferSize && !refillBuffer(false);
+    return bufferPos == bufferSize && !tryRefillBuffer(1);
   }
 
   /**
@@ -709,53 +1049,93 @@ public final class CodedInputStream {
       return totalBytesRetired + bufferPos;
   }
 
+  private interface RefillCallback {
+    void onRefill();
+  }
+
+  private RefillCallback refillCallback = null;
+
+  /**
+   * Ensures that at least {@code n} bytes are available in the buffer, reading
+   * more bytes from the input if necessary to make it so.  Caller must ensure
+   * that the requested space is less than BUFFER_SIZE.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  private void ensureAvailable(int n) throws IOException {
+    if (bufferSize - bufferPos < n) {
+      refillBuffer(n);
+    }
+  }
+
   /**
-   * Called with {@code this.buffer} is empty to read more bytes from the
-   * input.  If {@code mustSucceed} is true, refillBuffer() guarantees that
-   * either there will be at least one byte in the buffer when it returns
-   * or it will throw an exception.  If {@code mustSucceed} is false,
-   * refillBuffer() returns false if no more bytes were available.
+   * Reads more bytes from the input, making at least {@code n} bytes available
+   * in the buffer.  Caller must ensure that the requested space is not yet
+   * available, and that the requested space is less than BUFFER_SIZE.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current
+   *                                        limit was reached.
    */
-  private boolean refillBuffer(final boolean mustSucceed) throws IOException {
-    if (bufferPos < bufferSize) {
+  private void refillBuffer(int n) throws IOException {
+    if (!tryRefillBuffer(n)) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+  }
+
+  /**
+   * Tries to read more bytes from the input, making at least {@code n} bytes
+   * available in the buffer.  Caller must ensure that the requested space is
+   * not yet available, and that the requested space is less than BUFFER_SIZE.
+   *
+   * @return {@code true} if the bytes could be made available; {@code false}
+   *         if the end of the stream or the current limit was reached.
+   */
+  private boolean tryRefillBuffer(int n) throws IOException {
+    if (bufferPos + n <= bufferSize) {
       throw new IllegalStateException(
-        "refillBuffer() called when buffer wasn't empty.");
+          "refillBuffer() called when " + n +
+          " bytes were already available in buffer");
     }
 
-    if (totalBytesRetired + bufferSize == currentLimit) {
+    if (totalBytesRetired + bufferPos + n > currentLimit) {
       // Oops, we hit a limit.
-      if (mustSucceed) {
-        throw InvalidProtocolBufferException.truncatedMessage();
-      } else {
-        return false;
-      }
+      return false;
     }
 
-    totalBytesRetired += bufferSize;
-
-    bufferPos = 0;
-    bufferSize = (input == null) ? -1 : input.read(buffer);
-    if (bufferSize == 0 || bufferSize < -1) {
-      throw new IllegalStateException(
-          "InputStream#read(byte[]) returned invalid result: " + bufferSize +
-          "\nThe InputStream implementation is buggy.");
+    if (refillCallback != null) {
+      refillCallback.onRefill();
     }
-    if (bufferSize == -1) {
-      bufferSize = 0;
-      if (mustSucceed) {
-        throw InvalidProtocolBufferException.truncatedMessage();
-      } else {
-        return false;
+
+    if (input != null) {
+      int pos = bufferPos;
+      if (pos > 0) {
+        if (bufferSize > pos) {
+          System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos);
+        }
+        totalBytesRetired += pos;
+        bufferSize -= pos;
+        bufferPos = 0;
       }
-    } else {
-      recomputeBufferSizeAfterLimit();
-      final int totalBytesRead =
-        totalBytesRetired + bufferSize + bufferSizeAfterLimit;
-      if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
-        throw InvalidProtocolBufferException.sizeLimitExceeded();
+
+      int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
+      if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
+        throw new IllegalStateException(
+            "InputStream#read(byte[]) returned invalid result: " + bytesRead +
+            "\nThe InputStream implementation is buggy.");
+      }
+      if (bytesRead > 0) {
+        bufferSize += bytesRead;
+        // Integer-overflow-conscious check against sizeLimit
+        if (totalBytesRetired + n - sizeLimit > 0) {
+          throw InvalidProtocolBufferException.sizeLimitExceeded();
+        }
+        recomputeBufferSizeAfterLimit();
+        return (bufferSize >= n) ? true : tryRefillBuffer(n);
       }
-      return true;
     }
+
+    return false;
   }
 
   /**
@@ -766,7 +1146,7 @@ public final class CodedInputStream {
    */
   public byte readRawByte() throws IOException {
     if (bufferPos == bufferSize) {
-      refillBuffer(true);
+      refillBuffer(1);
     }
     return buffer[bufferPos++];
   }
@@ -778,8 +1158,26 @@ public final class CodedInputStream {
    *                                        limit was reached.
    */
   public byte[] readRawBytes(final int size) throws IOException {
-    if (size < 0) {
-      throw InvalidProtocolBufferException.negativeSize();
+    final int pos = bufferPos;
+    if (size <= (bufferSize - pos) && size > 0) {
+      bufferPos = pos + size;
+      return Arrays.copyOfRange(buffer, pos, pos + size);
+    } else {
+      return readRawBytesSlowPath(size);
+    }
+  }
+
+  /**
+   * Exactly like readRawBytes, but caller must have already checked the fast
+   * path: (size <= (bufferSize - pos) && size > 0)
+   */
+  private byte[] readRawBytesSlowPath(final int size) throws IOException {
+    if (size <= 0) {
+      if (size == 0) {
+        return Internal.EMPTY_BYTE_ARRAY;
+      } else {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
     }
 
     if (totalBytesRetired + bufferPos + size > currentLimit) {
@@ -789,13 +1187,7 @@ public final class CodedInputStream {
       throw InvalidProtocolBufferException.truncatedMessage();
     }
 
-    if (size <= bufferSize - bufferPos) {
-      // We have all the bytes we need already.
-      final byte[] bytes = new byte[size];
-      System.arraycopy(buffer, bufferPos, bytes, 0, size);
-      bufferPos += size;
-      return bytes;
-    } else if (size < BUFFER_SIZE) {
+    if (size < BUFFER_SIZE) {
       // Reading more bytes than are in the buffer, but not an excessive number
       // of bytes.  We can safely allocate the resulting array ahead of time.
 
@@ -805,18 +1197,10 @@ public final class CodedInputStream {
       System.arraycopy(buffer, bufferPos, bytes, 0, pos);
       bufferPos = bufferSize;
 
-      // We want to use refillBuffer() and then copy from the buffer into our
+      // We want to refill the buffer and then copy from the buffer into our
       // byte array rather than reading directly into our byte array because
       // the input may be unbuffered.
-      refillBuffer(true);
-
-      while (size - pos > bufferSize) {
-        System.arraycopy(buffer, 0, bytes, pos, bufferSize);
-        pos += bufferSize;
-        bufferPos = bufferSize;
-        refillBuffer(true);
-      }
-
+      ensureAvailable(size - pos);
       System.arraycopy(buffer, 0, bytes, pos, size - pos);
       bufferPos = size - pos;
 
@@ -885,6 +1269,19 @@ public final class CodedInputStream {
    *                                        limit was reached.
    */
   public void skipRawBytes(final int size) throws IOException {
+    if (size <= (bufferSize - bufferPos) && size >= 0) {
+      // We have all the bytes we need already.
+      bufferPos += size;
+    } else {
+      skipRawBytesSlowPath(size);
+    }
+  }
+
+  /**
+   * Exactly like skipRawBytes, but caller must have already checked the fast
+   * path: (size <= (bufferSize - pos) && size >= 0)
+   */
+  private void skipRawBytesSlowPath(final int size) throws IOException {
     if (size < 0) {
       throw InvalidProtocolBufferException.negativeSize();
     }
@@ -896,25 +1293,19 @@ public final class CodedInputStream {
       throw InvalidProtocolBufferException.truncatedMessage();
     }
 
-    if (size <= bufferSize - bufferPos) {
-      // We have all the bytes we need already.
-      bufferPos += size;
-    } else {
-      // Skipping more bytes than are in the buffer.  First skip what we have.
-      int pos = bufferSize - bufferPos;
-      bufferPos = bufferSize;
-
-      // Keep refilling the buffer until we get to the point we wanted to skip
-      // to.  This has the side effect of ensuring the limits are updated
-      // correctly.
-      refillBuffer(true);
-      while (size - pos > bufferSize) {
-        pos += bufferSize;
-        bufferPos = bufferSize;
-        refillBuffer(true);
-      }
+    // Skipping more bytes than are in the buffer.  First skip what we have.
+    int pos = bufferSize - bufferPos;
+    bufferPos = bufferSize;
 
-      bufferPos = size - pos;
+    // Keep refilling the buffer until we get to the point we wanted to skip to.
+    // This has the side effect of ensuring the limits are updated correctly.
+    refillBuffer(1);
+    while (size - pos > bufferSize) {
+      pos += bufferSize;
+      bufferPos = bufferSize;
+      refillBuffer(1);
     }
+
+    bufferPos = size - pos;
   }
 }

+ 208 - 22
java/src/main/java/com/google/protobuf/CodedOutputStream.java

@@ -31,9 +31,9 @@
 package com.google.protobuf;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
 
 /**
  * Encodes and writes protocol message fields.
@@ -53,6 +53,7 @@ public final class CodedOutputStream {
   private final byte[] buffer;
   private final int limit;
   private int position;
+  private int totalBytesWritten = 0;
 
   private final OutputStream output;
 
@@ -129,6 +130,38 @@ public final class CodedOutputStream {
     return new CodedOutputStream(flatArray, offset, length);
   }
 
+  /**
+   * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+   */
+  public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
+    return newInstance(byteBuffer, DEFAULT_BUFFER_SIZE);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+   */
+  public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
+      int bufferSize) {
+    return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize);
+  }
+  
+  private static class ByteBufferOutputStream extends OutputStream {
+    private final ByteBuffer byteBuffer;
+    public ByteBufferOutputStream(ByteBuffer byteBuffer) {
+      this.byteBuffer = byteBuffer;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+      byteBuffer.put((byte) b);
+    }
+
+    @Override
+    public void write(byte[] data, int offset, int length) throws IOException {
+      byteBuffer.put(data, offset, length);
+    }
+  }
+
   // -----------------------------------------------------------------
 
   /** Write a {@code double} field, including tag, to the stream. */
@@ -202,6 +235,7 @@ public final class CodedOutputStream {
     writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
   }
 
+
   /**
    * Write a group represented by an {@link UnknownFieldSet}.
    *
@@ -222,6 +256,7 @@ public final class CodedOutputStream {
     writeMessageNoTag(value);
   }
 
+
   /** Write a {@code bytes} field, including tag, to the stream. */
   public void writeBytes(final int fieldNumber, final ByteString value)
                          throws IOException {
@@ -229,6 +264,39 @@ public final class CodedOutputStream {
     writeBytesNoTag(value);
   }
 
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  public void writeByteArray(final int fieldNumber, final byte[] value)
+                             throws IOException {
+    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    writeByteArrayNoTag(value);
+  }
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  public void writeByteArray(final int fieldNumber,
+                             final byte[] value,
+                             final int offset,
+                             final int length)
+                             throws IOException {
+    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    writeByteArrayNoTag(value, offset, length);
+  }
+
+  /**
+   * Write a {@code bytes} field, including tag, to the stream.
+   * This method will write all content of the ByteBuffer regardless of the
+   * current position and limit (i.e., the number of bytes to be written is
+   * value.capacity(), not value.remaining()). Furthermore, this method doesn't
+   * alter the state of the passed-in ByteBuffer. Its position, limit, mark,
+   * etc. will remain unchanged. If you only want to write the remaining bytes
+   * of a ByteBuffer, you can call
+   * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
+   */
+  public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+      throws IOException {
+    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    writeByteBufferNoTag(value);
+  }
+
   /** Write a {@code uint32} field, including tag, to the stream. */
   public void writeUInt32(final int fieldNumber, final int value)
                           throws IOException {
@@ -362,6 +430,7 @@ public final class CodedOutputStream {
     value.writeTo(this);
   }
 
+
   /**
    * Write a group represented by an {@link UnknownFieldSet}.
    *
@@ -380,12 +449,41 @@ public final class CodedOutputStream {
     value.writeTo(this);
   }
 
+
   /** Write a {@code bytes} field to the stream. */
   public void writeBytesNoTag(final ByteString value) throws IOException {
     writeRawVarint32(value.size());
     writeRawBytes(value);
   }
 
+  /** Write a {@code bytes} field to the stream. */
+  public void writeByteArrayNoTag(final byte[] value) throws IOException {
+    writeRawVarint32(value.length);
+    writeRawBytes(value);
+  }
+
+  /** Write a {@code bytes} field to the stream. */
+  public void writeByteArrayNoTag(final byte[] value,
+                                  final int offset,
+                                  final int length) throws IOException {
+    writeRawVarint32(length);
+    writeRawBytes(value, offset, length);
+  }
+
+  /**
+   * Write a {@code bytes} field to the stream.  This method will write all
+   * content of the ByteBuffer regardless of the current position and limit
+   * (i.e., the number of bytes to be written is value.capacity(), not
+   * value.remaining()). Furthermore, this method doesn't alter the state of
+   * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain
+   * unchanged. If you only want to write the remaining bytes of a ByteBuffer,
+   * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}.
+   */
+  public void writeByteBufferNoTag(final ByteBuffer value) throws IOException {
+    writeRawVarint32(value.capacity());
+    writeRawBytes(value);
+  }
+
   /** Write a {@code uint32} field to the stream. */
   public void writeUInt32NoTag(final int value) throws IOException {
     writeRawVarint32(value);
@@ -539,12 +637,30 @@ public final class CodedOutputStream {
     return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
   }
 
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeByteArraySize(final int fieldNumber,
+                                         final byte[] value) {
+    return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeByteBufferSize(final int fieldNumber,
+                                         final ByteBuffer value) {
+    return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
+  }
+
   /**
    * Compute the number of bytes that would be needed to encode an
    * embedded message in lazy field, including tag.
    */
   public static int computeLazyFieldSize(final int fieldNumber,
-                                         final LazyField value) {
+                                         final LazyFieldLite value) {
     return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
   }
 
@@ -629,7 +745,7 @@ public final class CodedOutputStream {
    * historical reasons, the wire format differs from normal fields.
    */
   public static int computeLazyFieldMessageSetExtensionSize(
-      final int fieldNumber, final LazyField value) {
+      final int fieldNumber, final LazyFieldLite value) {
     return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
            computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
            computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
@@ -754,7 +870,7 @@ public final class CodedOutputStream {
    * Compute the number of bytes that would be needed to encode an embedded
    * message stored in lazy field.
    */
-  public static int computeLazyFieldSizeNoTag(final LazyField value) {
+  public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
     final int size = value.getSerializedSize();
     return computeRawVarint32Size(size) + size;
   }
@@ -768,6 +884,22 @@ public final class CodedOutputStream {
            value.size();
   }
 
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeByteArraySizeNoTag(final byte[] value) {
+    return computeRawVarint32Size(value.length) + value.length;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
+    return computeRawVarint32Size(value.capacity()) + value.capacity();
+  }
+
   /**
    * Compute the number of bytes that would be needed to encode a
    * {@code uint32} field.
@@ -886,6 +1018,15 @@ public final class CodedOutputStream {
     }
   }
 
+  /**
+   * Get the total number of bytes successfully written to this stream.  The
+   * returned value is not guaranteed to be accurate if exceptions have been
+   * found in the middle of writing.
+   */
+  public int getTotalBytesWritten() {
+    return totalBytesWritten;
+  }
+
   /** Write a single byte. */
   public void writeRawByte(final byte value) throws IOException {
     if (position == limit) {
@@ -893,6 +1034,7 @@ public final class CodedOutputStream {
     }
 
     buffer[position++] = value;
+    ++totalBytesWritten;
   }
 
   /** Write a single byte, represented by an integer value. */
@@ -910,6 +1052,61 @@ public final class CodedOutputStream {
     writeRawBytes(value, 0, value.length);
   }
 
+  /**
+   * Write a ByteBuffer. This method will write all content of the ByteBuffer
+   * regardless of the current position and limit (i.e., the number of bytes
+   * to be written is value.capacity(), not value.remaining()). Furthermore,
+   * this method doesn't alter the state of the passed-in ByteBuffer. Its
+   * position, limit, mark, etc. will remain unchanged. If you only want to
+   * write the remaining bytes of a ByteBuffer, you can call
+   * {@code writeRawBytes(byteBuffer.slice())}.
+   */
+  public void writeRawBytes(final ByteBuffer value) throws IOException {
+    if (value.hasArray()) {
+      writeRawBytes(value.array(), value.arrayOffset(), value.capacity());
+    } else {
+      ByteBuffer duplicated = value.duplicate();
+      duplicated.clear();
+      writeRawBytesInternal(duplicated);
+    }
+  }
+
+  /** Write a ByteBuffer that isn't backed by an array. */
+  private void writeRawBytesInternal(final ByteBuffer value)
+      throws IOException {
+    int length = value.remaining();
+    if (limit - position >= length) {
+      // We have room in the current buffer.
+      value.get(buffer, position, length);
+      position += length;
+      totalBytesWritten += length;
+    } else {
+      // Write extends past current buffer.  Fill the rest of this buffer and
+      // flush.
+      final int bytesWritten = limit - position;
+      value.get(buffer, position, bytesWritten);
+      length -= bytesWritten;
+      position = limit;
+      totalBytesWritten += bytesWritten;
+      refreshBuffer();
+
+      // Now deal with the rest.
+      // Since we have an output stream, this is our buffer
+      // and buffer offset == 0
+      while (length > limit) {
+        // Copy data into the buffer before writing it to OutputStream.
+        // TODO(xiaofeng): Introduce ZeroCopyOutputStream to avoid this copy.
+        value.get(buffer, 0, limit);
+        output.write(buffer, 0, limit);
+        length -= limit;
+        totalBytesWritten += limit;
+      }
+      value.get(buffer, 0, length);
+      position = length;
+      totalBytesWritten += length;
+    }
+  }
+
   /** Write part of an array of bytes. */
   public void writeRawBytes(final byte[] value, int offset, int length)
                             throws IOException {
@@ -917,6 +1114,7 @@ public final class CodedOutputStream {
       // We have room in the current buffer.
       System.arraycopy(value, offset, buffer, position, length);
       position += length;
+      totalBytesWritten += length;
     } else {
       // Write extends past current buffer.  Fill the rest of this buffer and
       // flush.
@@ -925,6 +1123,7 @@ public final class CodedOutputStream {
       offset += bytesWritten;
       length -= bytesWritten;
       position = limit;
+      totalBytesWritten += bytesWritten;
       refreshBuffer();
 
       // Now deal with the rest.
@@ -938,6 +1137,7 @@ public final class CodedOutputStream {
         // Write is very big.  Let's do it all at once.
         output.write(value, offset, length);
       }
+      totalBytesWritten += length;
     }
   }
 
@@ -948,6 +1148,7 @@ public final class CodedOutputStream {
       // We have room in the current buffer.
       value.copyTo(buffer, offset, position, length);
       position += length;
+      totalBytesWritten += length;
     } else {
       // Write extends past current buffer.  Fill the rest of this buffer and
       // flush.
@@ -956,6 +1157,7 @@ public final class CodedOutputStream {
       offset += bytesWritten;
       length -= bytesWritten;
       position = limit;
+      totalBytesWritten += bytesWritten;
       refreshBuffer();
 
       // Now deal with the rest.
@@ -966,25 +1168,9 @@ public final class CodedOutputStream {
         value.copyTo(buffer, offset, 0, length);
         position = length;
       } else {
-        // Write is very big, but we can't do it all at once without allocating
-        // an a copy of the byte array since ByteString does not give us access
-        // to the underlying bytes. Use the InputStream interface on the
-        // ByteString and our buffer to copy between the two.
-        InputStream inputStreamFrom = value.newInput();
-        if (offset != inputStreamFrom.skip(offset)) {
-          throw new IllegalStateException("Skip failed? Should never happen.");
-        }
-        // Use the buffer as the temporary buffer to avoid allocating memory.
-        while (length > 0) {
-          int bytesToRead = Math.min(length, limit);
-          int bytesRead = inputStreamFrom.read(buffer, 0, bytesToRead);
-          if (bytesRead != bytesToRead) {
-            throw new IllegalStateException("Read failed? Should never happen");
-          }
-          output.write(buffer, 0, bytesRead);
-          length -= bytesRead;
-        }
+        value.writeTo(output, offset, length);
       }
+      totalBytesWritten += length;
     }
   }
 

+ 316 - 48
java/src/main/java/com/google/protobuf/Descriptors.java

@@ -32,6 +32,7 @@ package com.google.protobuf;
 
 import com.google.protobuf.DescriptorProtos.*;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -39,6 +40,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Logger;
 import java.io.UnsupportedEncodingException;
 
 /**
@@ -60,19 +62,27 @@ import java.io.UnsupportedEncodingException;
  * @author kenton@google.com Kenton Varda
  */
 public final class Descriptors {
+  private static final Logger logger =
+      Logger.getLogger(Descriptors.class.getName());
   /**
    * Describes a {@code .proto} file, including everything defined within.
    * That includes, in particular, descriptors for all the messages and
    * file descriptors for all other imported {@code .proto} files
    * (dependencies).
    */
-  public static final class FileDescriptor {
+  public static final class FileDescriptor extends GenericDescriptor {
     /** Convert the descriptor to its protocol message representation. */
     public FileDescriptorProto toProto() { return proto; }
 
     /** Get the file name. */
     public String getName() { return proto.getName(); }
 
+    /** Returns this object. */
+    public FileDescriptor getFile() { return this; }
+
+    /** Returns the same as getName(). */
+    public String getFullName() { return proto.getName(); }
+
     /**
      * Get the proto package name.  This is the package name given by the
      * {@code package} statement in the {@code .proto} file, which differs
@@ -213,8 +223,7 @@ public final class Descriptors {
      *
      * @param proto The protocol message form of the FileDescriptor.
      * @param dependencies {@code FileDescriptor}s corresponding to all of
-     *                     the file's dependencies, in the exact order listed
-     *                     in {@code proto}.
+     *                     the file's dependencies.
      * @throws DescriptorValidationException {@code proto} is not a valid
      *           descriptor.  This can occur for a number of reasons, e.g.
      *           because a field has an undefined type or because two messages
@@ -223,6 +232,28 @@ public final class Descriptors {
     public static FileDescriptor buildFrom(final FileDescriptorProto proto,
                                            final FileDescriptor[] dependencies)
                                     throws DescriptorValidationException {
+      return buildFrom(proto, dependencies, false);
+    }
+    
+
+    /**
+     * Construct a {@code FileDescriptor}.
+     *
+     * @param proto The protocol message form of the FileDescriptor.
+     * @param dependencies {@code FileDescriptor}s corresponding to all of
+     *                     the file's dependencies.
+     * @param allowUnknownDependencies If true, non-exist dependenncies will be
+     *           ignored and undefined message types will be replaced with a
+     *           placeholder type.
+     * @throws DescriptorValidationException {@code proto} is not a valid
+     *           descriptor.  This can occur for a number of reasons, e.g.
+     *           because a field has an undefined type or because two messages
+     *           were defined with the same name.
+     */
+    private static FileDescriptor buildFrom(
+        final FileDescriptorProto proto, final FileDescriptor[] dependencies,
+        final boolean allowUnknownDependencies)
+        throws DescriptorValidationException {
       // Building descriptors involves two steps:  translating and linking.
       // In the translation step (implemented by FileDescriptor's
       // constructor), we build an object tree mirroring the
@@ -232,23 +263,10 @@ public final class Descriptors {
       // FieldDescriptor for an embedded message contains a pointer directly
       // to the Descriptor for that message's type.  We also detect undefined
       // types in the linking step.
-      final DescriptorPool pool = new DescriptorPool(dependencies);
-      final FileDescriptor result =
-          new FileDescriptor(proto, dependencies, pool);
-
-      if (dependencies.length != proto.getDependencyCount()) {
-        throw new DescriptorValidationException(result,
-          "Dependencies passed to FileDescriptor.buildFrom() don't match " +
-          "those listed in the FileDescriptorProto.");
-      }
-      for (int i = 0; i < proto.getDependencyCount(); i++) {
-        if (!dependencies[i].getName().equals(proto.getDependency(i))) {
-          throw new DescriptorValidationException(result,
-            "Dependencies passed to FileDescriptor.buildFrom() don't match " +
-            "those listed in the FileDescriptorProto.");
-        }
-      }
-
+      final DescriptorPool pool = new DescriptorPool(
+          dependencies, allowUnknownDependencies);
+      final FileDescriptor result = new FileDescriptor(
+          proto, dependencies, pool, allowUnknownDependencies);
       result.crossLink();
       return result;
     }
@@ -296,7 +314,9 @@ public final class Descriptors {
 
       final FileDescriptor result;
       try {
-        result = buildFrom(proto, dependencies);
+        // When building descriptors for generated code, we allow unknown
+        // dependencies by default.
+        result = buildFrom(proto, dependencies, true);
       } catch (DescriptorValidationException e) {
         throw new IllegalArgumentException(
           "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
@@ -319,6 +339,56 @@ public final class Descriptors {
       }
     }
 
+    /**
+     * This method is to be called by generated code only.  It uses Java
+     * reflection to load the dependencies' descriptors.
+     */
+    public static void internalBuildGeneratedFileFrom(
+        final String[] descriptorDataParts,
+        final Class<?> descriptorOuterClass,
+        final String[] dependencies,
+        final String[] dependencyFileNames,
+        final InternalDescriptorAssigner descriptorAssigner) {
+      List<FileDescriptor> descriptors = new ArrayList<FileDescriptor>();
+      for (int i = 0; i < dependencies.length; i++) {
+        try {
+          Class<?> clazz =
+              descriptorOuterClass.getClassLoader().loadClass(dependencies[i]);
+          descriptors.add(
+              (FileDescriptor) clazz.getField("descriptor").get(null));
+        } catch (Exception e) {
+          // We allow unknown dependencies by default. If a dependency cannot
+          // be found we only generate a warning.
+          logger.warning("Descriptors for \"" + dependencyFileNames[i] +
+              "\" can not be found.");
+        }
+      }
+      FileDescriptor[] descriptorArray = new FileDescriptor[descriptors.size()];
+      descriptors.toArray(descriptorArray);
+      internalBuildGeneratedFileFrom(
+          descriptorDataParts, descriptorArray, descriptorAssigner);
+    }
+
+    /**
+     * This method is to be called by generated code only.  It is used to
+     * update the FileDescriptorProto associated with the descriptor by
+     * parsing it again with the given ExtensionRegistry. This is needed to
+     * recognize custom options.
+     */
+    public static void internalUpdateFileDescriptor(
+        final FileDescriptor descriptor,
+        final ExtensionRegistry registry) {
+      ByteString bytes = descriptor.proto.toByteString();
+      FileDescriptorProto proto;
+      try {
+        proto = FileDescriptorProto.parseFrom(bytes, registry);
+      } catch (InvalidProtocolBufferException e) {
+        throw new IllegalArgumentException(
+          "Failed to parse protocol buffer descriptor for generated code.", e);
+      }
+      descriptor.setProto(proto);
+    }
+
     /**
      * This class should be used by generated code only.  When calling
      * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
@@ -346,22 +416,38 @@ public final class Descriptors {
 
     private FileDescriptor(final FileDescriptorProto proto,
                            final FileDescriptor[] dependencies,
-                           final DescriptorPool pool)
+                           final DescriptorPool pool,
+                           boolean allowUnknownDependencies)
                     throws DescriptorValidationException {
       this.pool = pool;
       this.proto = proto;
       this.dependencies = dependencies.clone();
-      this.publicDependencies =
-          new FileDescriptor[proto.getPublicDependencyCount()];
+      HashMap<String, FileDescriptor> nameToFileMap =
+          new HashMap<String, FileDescriptor>();
+      for (FileDescriptor file : dependencies) {
+        nameToFileMap.put(file.getName(), file);
+      }
+      List<FileDescriptor> publicDependencies = new ArrayList<FileDescriptor>();
       for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
         int index = proto.getPublicDependency(i);
-        if (index < 0 || index >= this.dependencies.length) {
+        if (index < 0 || index >= proto.getDependencyCount()) {
           throw new DescriptorValidationException(this,
               "Invalid public dependency index.");
         }
-        this.publicDependencies[i] =
-            this.dependencies[proto.getPublicDependency(i)];
+        String name = proto.getDependency(index);
+        FileDescriptor file = nameToFileMap.get(name);
+        if (file == null) {
+          if (!allowUnknownDependencies) {
+            throw new DescriptorValidationException(this,
+                "Invalid public dependency: " + name);
+          }
+          // Ignore unknown dependencies.
+        } else {
+          publicDependencies.add(file);
+        }
       }
+      this.publicDependencies = new FileDescriptor[publicDependencies.size()];
+      publicDependencies.toArray(this.publicDependencies);
 
       pool.addPackage(getPackage(), this);
 
@@ -387,6 +473,27 @@ public final class Descriptors {
           proto.getExtension(i), this, null, i, true);
       }
     }
+    
+    /**
+     * Create a placeholder FileDescriptor for a message Descriptor. 
+     */
+    FileDescriptor(String packageName, Descriptor message)
+        throws DescriptorValidationException {
+      this.pool = new DescriptorPool(new FileDescriptor[0], true);
+      this.proto = FileDescriptorProto.newBuilder()
+          .setName(message.getFullName() + ".placeholder.proto")
+          .setPackage(packageName).addMessageType(message.toProto()).build();
+      this.dependencies = new FileDescriptor[0];
+      this.publicDependencies = new FileDescriptor[0];
+
+      messageTypes = new Descriptor[] {message};
+      enumTypes = new EnumDescriptor[0];
+      services = new ServiceDescriptor[0];
+      extensions = new FieldDescriptor[0];
+
+      pool.addPackage(packageName, this);
+      pool.addSymbol(message);
+    }
 
     /** Look up and cross-link all field types, etc. */
     private void crossLink() throws DescriptorValidationException {
@@ -437,7 +544,7 @@ public final class Descriptors {
   // =================================================================
 
   /** Describes a message type. */
-  public static final class Descriptor implements GenericDescriptor {
+  public static final class Descriptor extends GenericDescriptor {
     /**
      * Get the index of this descriptor within its parent.  In other words,
      * given a {@link FileDescriptor} {@code file}, the following is true:
@@ -486,6 +593,11 @@ public final class Descriptors {
       return Collections.unmodifiableList(Arrays.asList(fields));
     }
 
+    /** Get a list of this message type's oneofs. */
+    public List<OneofDescriptor> getOneofs() {
+      return Collections.unmodifiableList(Arrays.asList(oneofs));
+    }
+
     /** Get a list of this message type's extensions. */
     public List<FieldDescriptor> getExtensions() {
       return Collections.unmodifiableList(Arrays.asList(extensions));
@@ -512,6 +624,14 @@ public final class Descriptors {
       return false;
     }
 
+    /**
+     * Indicates whether the message can be extended.  That is, whether it has
+     * any "extensions x to y" ranges declared on it.
+     */
+    public boolean isExtendable() {
+      return proto.getExtensionRangeList().size() != 0;
+    }
+
     /**
      * Finds a field by name.
      * @param name The unqualified name of the field (e.g. "foo").
@@ -576,6 +696,33 @@ public final class Descriptors {
     private final EnumDescriptor[] enumTypes;
     private final FieldDescriptor[] fields;
     private final FieldDescriptor[] extensions;
+    private final OneofDescriptor[] oneofs;
+
+    // Used to create a placeholder when the type cannot be found.
+    Descriptor(final String fullname) throws DescriptorValidationException {
+      String name = fullname;
+      String packageName = "";
+      int pos = fullname.lastIndexOf('.');
+      if (pos != -1) {
+        name = fullname.substring(pos + 1);
+        packageName = fullname.substring(0, pos);
+      }
+      this.index = 0;
+      this.proto = DescriptorProto.newBuilder().setName(name).addExtensionRange(
+          DescriptorProto.ExtensionRange.newBuilder().setStart(1)
+          .setEnd(536870912).build()).build();
+      this.fullName = fullname;
+      this.containingType = null;
+
+      this.nestedTypes = new Descriptor[0];
+      this.enumTypes = new EnumDescriptor[0];
+      this.fields = new FieldDescriptor[0];
+      this.extensions = new FieldDescriptor[0];
+      this.oneofs = new OneofDescriptor[0];
+      
+      // Create a placeholder FileDescriptor to hold this message.
+      this.file = new FileDescriptor(packageName, this);
+    }
 
     private Descriptor(final DescriptorProto proto,
                        final FileDescriptor file,
@@ -588,6 +735,12 @@ public final class Descriptors {
       this.file = file;
       containingType = parent;
 
+      oneofs = new OneofDescriptor[proto.getOneofDeclCount()];
+      for (int i = 0; i < proto.getOneofDeclCount(); i++) {
+        oneofs[i] = new OneofDescriptor(
+          proto.getOneofDecl(i), file, this, i);
+      }
+
       nestedTypes = new Descriptor[proto.getNestedTypeCount()];
       for (int i = 0; i < proto.getNestedTypeCount(); i++) {
         nestedTypes[i] = new Descriptor(
@@ -612,6 +765,17 @@ public final class Descriptors {
           proto.getExtension(i), file, this, i, true);
       }
 
+      for (int i = 0; i < proto.getOneofDeclCount(); i++) {
+        oneofs[i].fields = new FieldDescriptor[oneofs[i].getFieldCount()];
+        oneofs[i].fieldCount = 0;
+      }
+      for (int i = 0; i < proto.getFieldCount(); i++) {
+        OneofDescriptor oneofDescriptor = fields[i].getContainingOneof();
+        if (oneofDescriptor != null) {
+          oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
+        }
+      }
+
       file.pool.addSymbol(this);
     }
 
@@ -656,7 +820,8 @@ public final class Descriptors {
 
   /** Describes a field of a message type. */
   public static final class FieldDescriptor
-      implements GenericDescriptor, Comparable<FieldDescriptor>,
+        extends GenericDescriptor
+        implements Comparable<FieldDescriptor>,
                  FieldSet.FieldDescriptorLite<FieldDescriptor> {
     /**
      * Get the index of this descriptor within its parent.
@@ -700,6 +865,12 @@ public final class Descriptors {
     public WireFormat.FieldType getLiteType() {
       return table[type.ordinal()];
     }
+
+    /** For internal use only. */
+    public boolean needsUtf8Check() {
+      return (type == Type.STRING) && (getFile().getOptions().getJavaStringCheckUtf8());
+    }
+
     // I'm pretty sure values() constructs a new array every time, since there
     // is nothing stopping the caller from mutating the array.  Therefore we
     // make a static copy here.
@@ -761,6 +932,9 @@ public final class Descriptors {
      */
     public Descriptor getContainingType() { return containingType; }
 
+    /** Get the field's containing oneof. */
+    public OneofDescriptor getContainingOneof() { return containingOneof; }
+
     /**
      * For extensions defined nested within message types, gets the outer
      * type.  Not valid for non-extension fields.  For example, consider
@@ -838,6 +1012,7 @@ public final class Descriptors {
     private Type type;
     private Descriptor containingType;
     private Descriptor messageType;
+    private OneofDescriptor containingOneof;
     private EnumDescriptor enumType;
     private Object defaultValue;
 
@@ -946,12 +1121,31 @@ public final class Descriptors {
         } else {
           extensionScope = null;
         }
+
+        if (proto.hasOneofIndex()) {
+          throw new DescriptorValidationException(this,
+            "FieldDescriptorProto.oneof_index set for extension field.");
+        }
+        containingOneof = null;
       } else {
         if (proto.hasExtendee()) {
           throw new DescriptorValidationException(this,
             "FieldDescriptorProto.extendee set for non-extension field.");
         }
         containingType = parent;
+
+        if (proto.hasOneofIndex()) {
+          if (proto.getOneofIndex() < 0 ||
+              proto.getOneofIndex() >= parent.toProto().getOneofDeclCount()) {
+            throw new DescriptorValidationException(this,
+              "FieldDescriptorProto.oneof_index is out of range for type "
+              + parent.getName());
+          }
+          containingOneof = parent.getOneofs().get(proto.getOneofIndex());
+          containingOneof.fieldCount++;
+        } else {
+          containingOneof = null;
+        }
         extensionScope = null;
       }
 
@@ -1161,13 +1355,14 @@ public final class Descriptors {
       // down-cast and call mergeFrom directly.
       return ((Message.Builder) to).mergeFrom((Message) from);
     }
+
   }
 
   // =================================================================
 
   /** Describes an enum type. */
-  public static final class EnumDescriptor
-      implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
+  public static final class EnumDescriptor extends GenericDescriptor
+      implements Internal.EnumLiteMap<EnumValueDescriptor> {
     /**
      * Get the index of this descriptor within its parent.
      * @see Descriptors.Descriptor#getIndex()
@@ -1278,8 +1473,8 @@ public final class Descriptors {
    * with the same number after the first become aliases of the first.
    * However, they still have independent EnumValueDescriptors.
    */
-  public static final class EnumValueDescriptor
-      implements GenericDescriptor, Internal.EnumLite {
+  public static final class EnumValueDescriptor extends GenericDescriptor
+      implements Internal.EnumLite {
     /**
      * Get the index of this descriptor within its parent.
      * @see Descriptors.Descriptor#getIndex()
@@ -1294,6 +1489,9 @@ public final class Descriptors {
 
     /** Get the value's number. */
     public int getNumber() { return proto.getNumber(); }
+    
+    @Override
+    public String toString() { return proto.getName(); }
 
     /**
      * Get the value's fully-qualified name.
@@ -1343,7 +1541,7 @@ public final class Descriptors {
   // =================================================================
 
   /** Describes a service type. */
-  public static final class ServiceDescriptor implements GenericDescriptor {
+  public static final class ServiceDescriptor extends GenericDescriptor {
     /**
      * Get the index of this descriptor within its parent.
      * * @see Descriptors.Descriptor#getIndex()
@@ -1433,7 +1631,7 @@ public final class Descriptors {
   /**
    * Describes one method within a service type.
    */
-  public static final class MethodDescriptor implements GenericDescriptor {
+  public static final class MethodDescriptor extends GenericDescriptor {
     /**
      * Get the index of this descriptor within its parent.
      * * @see Descriptors.Descriptor#getIndex()
@@ -1537,14 +1735,18 @@ public final class Descriptors {
   // =================================================================
 
   /**
-   * All descriptors except {@code FileDescriptor} implement this to make
-   * {@code DescriptorPool}'s life easier.
+   * All descriptors implement this to make it easier to implement tools like
+   * {@code DescriptorPool}.<p>
+   *
+   * This class is public so that the methods it exposes can be called from
+   * outside of this package. However, it should only be subclassed from
+   * nested classes of Descriptors.
    */
-  private interface GenericDescriptor {
-    Message toProto();
-    String getName();
-    String getFullName();
-    FileDescriptor getFile();
+  public abstract static class GenericDescriptor {
+    public abstract Message toProto();
+    public abstract String getName();
+    public abstract String getFullName();
+    public abstract FileDescriptor getFile();
   }
 
   /**
@@ -1620,8 +1822,10 @@ public final class Descriptors {
       TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
     }
     
-    DescriptorPool(final FileDescriptor[] dependencies) {
+    DescriptorPool(final FileDescriptor[] dependencies,
+        boolean allowUnknownDependencies) {
       this.dependencies = new HashSet<FileDescriptor>();
+      this.allowUnknownDependencies = allowUnknownDependencies;
 
       for (int i = 0; i < dependencies.length; i++) {
         this.dependencies.add(dependencies[i]);
@@ -1650,6 +1854,7 @@ public final class Descriptors {
     }
 
     private final Set<FileDescriptor> dependencies;
+    private boolean allowUnknownDependencies;
 
     private final Map<String, GenericDescriptor> descriptorsByName =
       new HashMap<String, GenericDescriptor>();
@@ -1718,9 +1923,11 @@ public final class Descriptors {
       // TODO(kenton):  This could be optimized in a number of ways.
 
       GenericDescriptor result;
+      String fullname;
       if (name.startsWith(".")) {
         // Fully-qualified name.
-        result = findSymbol(name.substring(1), filter);
+        fullname = name.substring(1);
+        result = findSymbol(fullname, filter);
       } else {
         // If "name" is a compound identifier, we want to search for the
         // first component of it, then search within it for the rest.
@@ -1752,6 +1959,7 @@ public final class Descriptors {
           // Chop off the last component of the scope.
           final int dotpos = scopeToTry.lastIndexOf(".");
           if (dotpos == -1) {
+            fullname = name;
             result = findSymbol(name, filter);
             break;
           } else {
@@ -1771,6 +1979,7 @@ public final class Descriptors {
                 scopeToTry.append(name);
                 result = findSymbol(scopeToTry.toString(), filter);
               }
+              fullname = scopeToTry.toString();
               break;
             }
 
@@ -1781,8 +1990,24 @@ public final class Descriptors {
       }
 
       if (result == null) {
-        throw new DescriptorValidationException(relativeTo,
-            '\"' + name + "\" is not defined.");
+        if (allowUnknownDependencies && filter == SearchFilter.TYPES_ONLY) {
+          logger.warning("The descriptor for message type \"" + name +
+              "\" can not be found and a placeholder is created for it");
+          // We create a dummy message descriptor here regardless of the
+          // expected type. If the type should be message, this dummy
+          // descriptor will work well and if the type should be enum, a
+          // DescriptorValidationException will be thrown latter. In either
+          // case, the code works as expected: we allow unknown message types
+          // but not unknwon enum types.
+          result = new Descriptor(fullname);
+          // Add the placeholder file as a dependency so we can find the
+          // placeholder symbol when resolving other references.
+          this.dependencies.add(result.getFile());
+          return result;
+        } else {
+          throw new DescriptorValidationException(relativeTo,
+              '\"' + name + "\" is not defined.");
+        }
       } else {
         return result;
       }
@@ -1826,7 +2051,7 @@ public final class Descriptors {
      * just as placeholders so that someone cannot define, say, a message type
      * that has the same name as an existing package.
      */
-    private static final class PackageDescriptor implements GenericDescriptor {
+    private static final class PackageDescriptor extends GenericDescriptor {
       public Message toProto()        { return file.toProto(); }
       public String getName()         { return name;           }
       public String getFullName()     { return fullName;       }
@@ -1911,7 +2136,7 @@ public final class Descriptors {
         fieldsByNumber.put(key, old);
         throw new DescriptorValidationException(field,
           "Field number " + field.getNumber() +
-          "has already been used in \"" +
+          " has already been used in \"" +
           field.getContainingType().getFullName() +
           "\" by field \"" + old.getName() + "\".");
       }
@@ -1967,4 +2192,47 @@ public final class Descriptors {
       }
     }
   }
+
+  /** Describes an oneof of a message type. */
+  public static final class OneofDescriptor {
+    /** Get the index of this descriptor within its parent. */
+    public int getIndex() { return index; }
+
+    public String getName() { return proto.getName(); }
+
+    public FileDescriptor getFile() { return file; }
+
+    public String getFullName() { return fullName; }
+
+    public Descriptor getContainingType() { return containingType; }
+
+    public int getFieldCount() { return fieldCount; }
+
+    public FieldDescriptor getField(int index) {
+      return fields[index];
+    }
+
+    private OneofDescriptor(final OneofDescriptorProto proto,
+                            final FileDescriptor file,
+                            final Descriptor parent,
+                            final int index)
+                     throws DescriptorValidationException {
+      this.proto = proto;
+      fullName = computeFullName(file, parent, proto.getName());
+      this.file = file;
+      this.index = index;
+
+      containingType = parent;
+      fieldCount = 0;
+    }
+
+    private final int index;
+    private OneofDescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+
+    private Descriptor containingType;
+    private int fieldCount;
+    private FieldDescriptor[] fields;
+  }
 }

+ 110 - 8
java/src/main/java/com/google/protobuf/DynamicMessage.java

@@ -32,6 +32,7 @@ package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
 
 import java.io.InputStream;
 import java.io.IOException;
@@ -47,16 +48,25 @@ import java.util.Map;
 public final class DynamicMessage extends AbstractMessage {
   private final Descriptor type;
   private final FieldSet<FieldDescriptor> fields;
+  private final FieldDescriptor[] oneofCases;
   private final UnknownFieldSet unknownFields;
   private int memoizedSize = -1;
 
   /**
    * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
+   * oneofCases stores the FieldDescriptor for each oneof to indicate
+   * which field is set. Caller should make sure the array is immutable.
+   *
+   * This contructor is package private and will be used in
+   * {@code DynamicMutableMessage} to convert a mutable message to an immutable
+   * message.
    */
-  private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
-                         UnknownFieldSet unknownFields) {
+  DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
+                 FieldDescriptor[] oneofCases,
+                 UnknownFieldSet unknownFields) {
     this.type = type;
     this.fields = fields;
+    this.oneofCases = oneofCases;
     this.unknownFields = unknownFields;
   }
 
@@ -65,10 +75,14 @@ public final class DynamicMessage extends AbstractMessage {
    * given type.
    */
   public static DynamicMessage getDefaultInstance(Descriptor type) {
+    int oneofDeclCount = type.toProto().getOneofDeclCount();
+    FieldDescriptor[] oneofCases = new FieldDescriptor[oneofDeclCount];
     return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
+                              oneofCases,
                               UnknownFieldSet.getDefaultInstance());
   }
 
+
   /** Parse a message of the given type from the given input stream. */
   public static DynamicMessage parseFrom(Descriptor type,
                                          CodedInputStream input)
@@ -152,6 +166,20 @@ public final class DynamicMessage extends AbstractMessage {
     return fields.getAllFields();
   }
 
+  public boolean hasOneof(OneofDescriptor oneof) {
+    verifyOneofContainingType(oneof);
+    FieldDescriptor field = oneofCases[oneof.getIndex()];
+    if (field == null) {
+      return false;
+    }
+    return true;
+  }
+
+  public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+    verifyOneofContainingType(oneof);
+    return oneofCases[oneof.getIndex()];
+  }
+
   public boolean hasField(FieldDescriptor field) {
     verifyContainingType(field);
     return fields.hasField(field);
@@ -186,8 +214,8 @@ public final class DynamicMessage extends AbstractMessage {
     return unknownFields;
   }
 
-  private static boolean isInitialized(Descriptor type,
-                                       FieldSet<FieldDescriptor> fields) {
+  static boolean isInitialized(Descriptor type,
+                               FieldSet<FieldDescriptor> fields) {
     // Check that all required fields are present.
     for (final FieldDescriptor field : type.getFields()) {
       if (field.isRequired()) {
@@ -270,6 +298,14 @@ public final class DynamicMessage extends AbstractMessage {
     }
   }
 
+  /** Verifies that the oneof is an oneof of this message. */
+  private void verifyOneofContainingType(OneofDescriptor oneof) {
+    if (oneof.getContainingType() != type) {
+      throw new IllegalArgumentException(
+        "OneofDescriptor does not match message type.");
+    }
+  }
+
   // =================================================================
 
   /**
@@ -278,6 +314,7 @@ public final class DynamicMessage extends AbstractMessage {
   public static final class Builder extends AbstractMessage.Builder<Builder> {
     private final Descriptor type;
     private FieldSet<FieldDescriptor> fields;
+    private final FieldDescriptor[] oneofCases;
     private UnknownFieldSet unknownFields;
 
     /** Construct a {@code Builder} for the given type. */
@@ -285,6 +322,7 @@ public final class DynamicMessage extends AbstractMessage {
       this.type = type;
       this.fields = FieldSet.newFieldSet();
       this.unknownFields = UnknownFieldSet.getDefaultInstance();
+      this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
     }
 
     // ---------------------------------------------------------------
@@ -313,6 +351,17 @@ public final class DynamicMessage extends AbstractMessage {
         ensureIsMutable();
         fields.mergeFrom(otherDynamicMessage.fields);
         mergeUnknownFields(otherDynamicMessage.unknownFields);
+        for (int i = 0; i < oneofCases.length; i++) {
+          if (oneofCases[i] == null) {
+            oneofCases[i] = otherDynamicMessage.oneofCases[i];
+          } else {
+            if ((otherDynamicMessage.oneofCases[i] != null)
+                && (oneofCases[i] != otherDynamicMessage.oneofCases[i])) {
+              fields.clearField(oneofCases[i]);
+              oneofCases[i] = otherDynamicMessage.oneofCases[i];
+            }
+          }
+        }
         return this;
       } else {
         return super.mergeFrom(other);
@@ -322,7 +371,8 @@ public final class DynamicMessage extends AbstractMessage {
     public DynamicMessage build() {
       if (!isInitialized()) {
         throw newUninitializedMessageException(
-          new DynamicMessage(type, fields, unknownFields));
+          new DynamicMessage(type, fields,
+              java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
       }
       return buildPartial();
     }
@@ -335,7 +385,8 @@ public final class DynamicMessage extends AbstractMessage {
     private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
       if (!isInitialized()) {
         throw newUninitializedMessageException(
-            new DynamicMessage(type, fields, unknownFields))
+          new DynamicMessage(type, fields,
+              java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields))
           .asInvalidProtocolBufferException();
       }
       return buildPartial();
@@ -344,7 +395,8 @@ public final class DynamicMessage extends AbstractMessage {
     public DynamicMessage buildPartial() {
       fields.makeImmutable();
       DynamicMessage result =
-        new DynamicMessage(type, fields, unknownFields);
+        new DynamicMessage(type, fields,
+            java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
       return result;
     }
 
@@ -353,6 +405,7 @@ public final class DynamicMessage extends AbstractMessage {
       Builder result = new Builder(type);
       result.fields.mergeFrom(fields);
       result.mergeUnknownFields(unknownFields);
+      System.arraycopy(oneofCases, 0, result.oneofCases, 0 , oneofCases.length);
       return result;
     }
 
@@ -383,6 +436,29 @@ public final class DynamicMessage extends AbstractMessage {
       return new Builder(field.getMessageType());
     }
 
+    public boolean hasOneof(OneofDescriptor oneof) {
+      verifyOneofContainingType(oneof);
+      FieldDescriptor field = oneofCases[oneof.getIndex()];
+      if (field == null) {
+        return false;
+      }
+      return true;
+    }
+
+    public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+      verifyOneofContainingType(oneof);
+      return oneofCases[oneof.getIndex()];
+    }
+
+    public Builder clearOneof(OneofDescriptor oneof) {
+      verifyOneofContainingType(oneof);
+      FieldDescriptor field = oneofCases[oneof.getIndex()];
+      if (field != null) {
+        clearField(field);
+      }
+      return this;
+    }
+
     public boolean hasField(FieldDescriptor field) {
       verifyContainingType(field);
       return fields.hasField(field);
@@ -392,7 +468,9 @@ public final class DynamicMessage extends AbstractMessage {
       verifyContainingType(field);
       Object result = fields.getField(field);
       if (result == null) {
-        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          result = Collections.emptyList();
+        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
           result = getDefaultInstance(field.getMessageType());
         } else {
           result = field.getDefaultValue();
@@ -404,6 +482,15 @@ public final class DynamicMessage extends AbstractMessage {
     public Builder setField(FieldDescriptor field, Object value) {
       verifyContainingType(field);
       ensureIsMutable();
+      OneofDescriptor oneofDescriptor = field.getContainingOneof();
+      if (oneofDescriptor != null) {
+        int index = oneofDescriptor.getIndex();
+        FieldDescriptor oldField = oneofCases[index];
+        if ((oldField != null) && (oldField != field)) {
+          fields.clearField(oldField);
+        }
+        oneofCases[index] = field;
+      }
       fields.setField(field, value);
       return this;
     }
@@ -411,6 +498,13 @@ public final class DynamicMessage extends AbstractMessage {
     public Builder clearField(FieldDescriptor field) {
       verifyContainingType(field);
       ensureIsMutable();
+      OneofDescriptor oneofDescriptor = field.getContainingOneof();
+      if (oneofDescriptor != null) {
+        int index = oneofDescriptor.getIndex();
+        if (oneofCases[index] == field) {
+          oneofCases[index] = null;
+        }
+      }
       fields.clearField(field);
       return this;
     }
@@ -466,6 +560,14 @@ public final class DynamicMessage extends AbstractMessage {
       }
     }
 
+    /** Verifies that the oneof is an oneof of this message. */
+    private void verifyOneofContainingType(OneofDescriptor oneof) {
+      if (oneof.getContainingType() != type) {
+        throw new IllegalArgumentException(
+          "OneofDescriptor does not match message type.");
+      }
+    }
+
     private void ensureIsMutable() {
       if (fields.isImmutable()) {
         fields = fields.clone();

+ 96 - 0
java/src/main/java/com/google/protobuf/Extension.java

@@ -0,0 +1,96 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Interface that generated extensions implement.
+ *
+ * @author liujisi@google.com (Jisi Liu)
+ */
+public abstract class Extension<ContainingType extends MessageLite, Type> {
+  /** Returns the field number of the extension. */
+  public abstract int getNumber();
+
+  /** Returns the type of the field. */
+  public abstract WireFormat.FieldType getLiteType();
+
+  /** Returns whether it is a repeated field. */
+  public abstract boolean isRepeated();
+
+  /** Returns the descriptor of the extension. */
+  public abstract Descriptors.FieldDescriptor getDescriptor();
+
+  /** Returns the default value of the extension field. */
+  public abstract Type getDefaultValue();
+
+  /**
+   * Returns the default instance of the extension field, if it's a message
+   * extension.
+   */
+  public abstract MessageLite getMessageDefaultInstance();
+
+  // All the methods below are extension implementation details.
+
+  /**
+   * The API type that the extension is used for.
+   */
+  protected enum ExtensionType {
+    IMMUTABLE,
+    MUTABLE,
+    PROTO1,
+  }
+
+  protected ExtensionType getExtensionType() {
+    // TODO(liujisi): make this abstract after we fix proto1.
+    return ExtensionType.IMMUTABLE;
+  }
+
+  /**
+   * Type of a message extension.
+   */
+  public enum MessageType {
+    PROTO1,
+    PROTO2,
+  }
+  
+  /**
+   * If the extension is a message extension (i.e., getLiteType() == MESSAGE),
+   * returns the type of the message, otherwise undefined.
+   */
+  public MessageType getMessageType() {
+    return MessageType.PROTO2;
+  }
+
+  protected abstract Object fromReflectionType(Object value);
+  protected abstract Object singularFromReflectionType(Object value);
+  protected abstract Object toReflectionType(Object value);
+  protected abstract Object singularToReflectionType(Object value);
+}

+ 156 - 30
java/src/main/java/com/google/protobuf/ExtensionRegistry.java

@@ -33,9 +33,12 @@ package com.google.protobuf;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * A table of known extensions, searchable by name or field number.  When
@@ -90,7 +93,7 @@ import java.util.Map;
  *
  * @author kenton@google.com Kenton Varda
  */
-public final class ExtensionRegistry extends ExtensionRegistryLite {
+public class ExtensionRegistry extends ExtensionRegistryLite {
   /** Construct a new, empty instance. */
   public static ExtensionRegistry newInstance() {
     return new ExtensionRegistry();
@@ -101,6 +104,7 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
     return EMPTY;
   }
 
+
   /** Returns an unmodifiable view of the registry. */
   @Override
   public ExtensionRegistry getUnmodifiable() {
@@ -130,42 +134,127 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
   }
 
   /**
-   * Find an extension by fully-qualified field name, in the proto namespace.
-   * I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
-   * a match is found.
+   * Deprecated. Use {@link #findImmutableExtensionByName(String)} instead.
+   */
+  public ExtensionInfo findExtensionByName(final String fullName) {
+    return findImmutableExtensionByName(fullName);
+  }
+
+  /**
+   * Find an extension for immutable APIs by fully-qualified field name,
+   * in the proto namespace. i.e. {@code result.descriptor.fullName()} will
+   * match {@code fullName} if a match is found.
    *
    * @return Information about the extension if found, or {@code null}
    *         otherwise.
    */
-  public ExtensionInfo findExtensionByName(final String fullName) {
-    return extensionsByName.get(fullName);
+  public ExtensionInfo findImmutableExtensionByName(final String fullName) {
+    return immutableExtensionsByName.get(fullName);
+  }
+
+  /**
+   * Find an extension for mutable APIs by fully-qualified field name,
+   * in the proto namespace. i.e. {@code result.descriptor.fullName()} will
+   * match {@code fullName} if a match is found.
+   *
+   * @return Information about the extension if found, or {@code null}
+   *         otherwise.
+   */
+  public ExtensionInfo findMutableExtensionByName(final String fullName) {
+    return mutableExtensionsByName.get(fullName);
   }
 
   /**
-   * Find an extension by containing type and field number.
+   * Deprecated. Use {@link #findImmutableExtensionByNumber(
+   * Descriptors.Descriptor, int)}
+   */
+  public ExtensionInfo findExtensionByNumber(
+      final Descriptor containingType, final int fieldNumber) {
+    return findImmutableExtensionByNumber(containingType, fieldNumber);
+  }
+
+  /**
+   * Find an extension by containing type and field number for immutable APIs.
    *
    * @return Information about the extension if found, or {@code null}
    *         otherwise.
    */
-  public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
-                                             final int fieldNumber) {
-    return extensionsByNumber.get(
+  public ExtensionInfo findImmutableExtensionByNumber(
+      final Descriptor containingType, final int fieldNumber) {
+    return immutableExtensionsByNumber.get(
       new DescriptorIntPair(containingType, fieldNumber));
   }
 
+  /**
+   * Find an extension by containing type and field number for mutable APIs.
+   *
+   * @return Information about the extension if found, or {@code null}
+   *         otherwise.
+   */
+  public ExtensionInfo findMutableExtensionByNumber(
+      final Descriptor containingType, final int fieldNumber) {
+    return mutableExtensionsByNumber.get(
+        new DescriptorIntPair(containingType, fieldNumber));
+  }
+
+  /**
+   * Find all extensions for mutable APIs by fully-qualified name of
+   * extended class. Note that this method is more computationally expensive
+   * than getting a single extension by name or number.
+   *
+   * @return Information about the extensions found, or {@code null} if there
+   *     are none.
+   */
+  public Set<ExtensionInfo> getAllMutableExtensionsByExtendedType(final String fullName) {
+    HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
+    for (DescriptorIntPair pair : mutableExtensionsByNumber.keySet()) {
+      if (pair.descriptor.getFullName().equals(fullName)) {
+        extensions.add(mutableExtensionsByNumber.get(pair));
+      }
+    }
+    return extensions;
+  }
+
+  /**
+   * Find all extensions for immutable APIs by fully-qualified name of
+   * extended class. Note that this method is more computationally expensive
+   * than getting a single extension by name or number.
+   *
+   * @return Information about the extensions found, or {@code null} if there
+   *     are none.
+   */
+  public Set<ExtensionInfo> getAllImmutableExtensionsByExtendedType(final String fullName) {
+    HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
+    for (DescriptorIntPair pair : immutableExtensionsByNumber.keySet()) {
+      if (pair.descriptor.getFullName().equals(fullName)) {
+        extensions.add(immutableExtensionsByNumber.get(pair));
+      }
+    }
+    return extensions;
+  }
+
   /** Add an extension from a generated file to the registry. */
-  public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
+  public void add(final Extension<?, ?> extension) {
+    if (extension.getExtensionType() != Extension.ExtensionType.IMMUTABLE &&
+        extension.getExtensionType() != Extension.ExtensionType.MUTABLE) {
+      // do not support other extension types. ignore
+      return;
+    }
+    add(newExtensionInfo(extension), extension.getExtensionType());
+  }
+
+  static ExtensionInfo newExtensionInfo(final Extension<?, ?> extension) {
     if (extension.getDescriptor().getJavaType() ==
         FieldDescriptor.JavaType.MESSAGE) {
       if (extension.getMessageDefaultInstance() == null) {
         throw new IllegalStateException(
             "Registered message-type extension had null default instance: " +
-            extension.getDescriptor().getFullName());
+                extension.getDescriptor().getFullName());
       }
-      add(new ExtensionInfo(extension.getDescriptor(),
-                            extension.getMessageDefaultInstance()));
+      return new ExtensionInfo(extension.getDescriptor(),
+          (Message) extension.getMessageDefaultInstance());
     } else {
-      add(new ExtensionInfo(extension.getDescriptor(), null));
+      return new ExtensionInfo(extension.getDescriptor(), null);
     }
   }
 
@@ -176,7 +265,9 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
         "ExtensionRegistry.add() must be provided a default instance when " +
         "adding an embedded message extension.");
     }
-    add(new ExtensionInfo(type, null));
+    ExtensionInfo info = new ExtensionInfo(type, null);
+    add(info, Extension.ExtensionType.IMMUTABLE);
+    add(info, Extension.ExtensionType.MUTABLE);
   }
 
   /** Add a message-type extension to the registry by descriptor. */
@@ -186,40 +277,75 @@ public final class ExtensionRegistry extends ExtensionRegistryLite {
         "ExtensionRegistry.add() provided a default instance for a " +
         "non-message extension.");
     }
-    add(new ExtensionInfo(type, defaultInstance));
+      add(new ExtensionInfo(type, defaultInstance),
+          Extension.ExtensionType.IMMUTABLE);
   }
 
   // =================================================================
   // Private stuff.
 
   private ExtensionRegistry() {
-    this.extensionsByName = new HashMap<String, ExtensionInfo>();
-    this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
+    this.immutableExtensionsByName = new HashMap<String, ExtensionInfo>();
+    this.mutableExtensionsByName = new HashMap<String, ExtensionInfo>();
+    this.immutableExtensionsByNumber =
+        new HashMap<DescriptorIntPair, ExtensionInfo>();
+    this.mutableExtensionsByNumber =
+        new HashMap<DescriptorIntPair, ExtensionInfo>();
   }
 
   private ExtensionRegistry(ExtensionRegistry other) {
     super(other);
-    this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
-    this.extensionsByNumber =
-        Collections.unmodifiableMap(other.extensionsByNumber);
+    this.immutableExtensionsByName =
+        Collections.unmodifiableMap(other.immutableExtensionsByName);
+    this.mutableExtensionsByName =
+        Collections.unmodifiableMap(other.mutableExtensionsByName);
+    this.immutableExtensionsByNumber =
+        Collections.unmodifiableMap(other.immutableExtensionsByNumber);
+    this.mutableExtensionsByNumber =
+            Collections.unmodifiableMap(other.mutableExtensionsByNumber);
   }
 
-  private final Map<String, ExtensionInfo> extensionsByName;
-  private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+  private final Map<String, ExtensionInfo> immutableExtensionsByName;
+  private final Map<String, ExtensionInfo> mutableExtensionsByName;
+  private final Map<DescriptorIntPair, ExtensionInfo> immutableExtensionsByNumber;
+  private final Map<DescriptorIntPair, ExtensionInfo> mutableExtensionsByNumber;
 
-  private ExtensionRegistry(boolean empty) {
+  ExtensionRegistry(boolean empty) {
     super(ExtensionRegistryLite.getEmptyRegistry());
-    this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
-    this.extensionsByNumber =
+    this.immutableExtensionsByName =
+        Collections.<String, ExtensionInfo>emptyMap();
+    this.mutableExtensionsByName =
+        Collections.<String, ExtensionInfo>emptyMap();
+    this.immutableExtensionsByNumber =
         Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
+    this.mutableExtensionsByNumber =
+            Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
   }
   private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
 
-  private void add(final ExtensionInfo extension) {
+  private void add(
+      final ExtensionInfo extension,
+      final Extension.ExtensionType extensionType) {
     if (!extension.descriptor.isExtension()) {
       throw new IllegalArgumentException(
-        "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
-        "(non-extension) field.");
+          "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
+              "(non-extension) field.");
+    }
+
+    Map<String, ExtensionInfo> extensionsByName;
+    Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+    switch (extensionType) {
+      case IMMUTABLE:
+        extensionsByName = immutableExtensionsByName;
+        extensionsByNumber = immutableExtensionsByNumber;
+        break;
+      case MUTABLE:
+        extensionsByName = mutableExtensionsByName;
+        extensionsByNumber = mutableExtensionsByNumber;
+        break;
+      default:
+        // Ignore the unknown supported type.
+        return;
     }
 
     extensionsByName.put(extension.descriptor.getFullName(), extension);

+ 73 - 27
java/src/main/java/com/google/protobuf/FieldSet.java

@@ -146,6 +146,7 @@ final class FieldSet<FieldDescriptorType extends
     return clone;
   }
 
+
   // =================================================================
 
   /** See {@link Message.Builder#clear()}. */
@@ -376,10 +377,13 @@ final class FieldSet<FieldDescriptorType extends
       case DOUBLE:       isValid = value instanceof Double    ; break;
       case BOOLEAN:      isValid = value instanceof Boolean   ; break;
       case STRING:       isValid = value instanceof String    ; break;
-      case BYTE_STRING:  isValid = value instanceof ByteString; break;
+      case BYTE_STRING:
+        isValid = value instanceof ByteString || value instanceof byte[];
+        break;
       case ENUM:
         // TODO(kenton):  Caller must do type checking here, I guess.
-        isValid = value instanceof Internal.EnumLite;
+        isValid =
+            (value instanceof Integer || value instanceof Internal.EnumLite);
         break;
       case MESSAGE:
         // TODO(kenton):  Caller must do type checking here, I guess.
@@ -483,6 +487,17 @@ final class FieldSet<FieldDescriptorType extends
     }
   }
 
+  private Object cloneIfMutable(Object value) {
+    if (value instanceof byte[]) {
+      byte[] bytes = (byte[]) value;
+      byte[] copy = new byte[bytes.length];
+      System.arraycopy(bytes, 0, copy, 0, bytes.length);
+      return copy;
+    } else {
+      return value;
+    }
+  }
+
   @SuppressWarnings({"unchecked", "rawtypes"})
   private void mergeFromField(
       final Map.Entry<FieldDescriptorType, Object> entry) {
@@ -495,28 +510,26 @@ final class FieldSet<FieldDescriptorType extends
     if (descriptor.isRepeated()) {
       Object value = getField(descriptor);
       if (value == null) {
-        // Our list is empty, but we still need to make a defensive copy of
-        // the other list since we don't know if the other FieldSet is still
-        // mutable.
-        fields.put(descriptor, new ArrayList((List) otherValue));
-      } else {
-        // Concatenate the lists.
-        ((List) value).addAll((List) otherValue);
+        value = new ArrayList();
+      }
+      for (Object element : (List) otherValue) {
+        ((List) value).add(cloneIfMutable(element));
       }
+      fields.put(descriptor, value);
     } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
       Object value = getField(descriptor);
       if (value == null) {
-        fields.put(descriptor, otherValue);
+        fields.put(descriptor, cloneIfMutable(otherValue));
       } else {
         // Merge the messages.
-        fields.put(
-            descriptor,
-            descriptor.internalMergeFrom(
+          value = descriptor.internalMergeFrom(
                 ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
-            .build());
+                .build();
+
+        fields.put(descriptor, value);
       }
     } else {
-      fields.put(descriptor, otherValue);
+      fields.put(descriptor, cloneIfMutable(otherValue));
     }
   }
 
@@ -524,11 +537,13 @@ final class FieldSet<FieldDescriptorType extends
   //   other class.  Probably WireFormat.
 
   /**
-   * Read a field of any primitive type from a CodedInputStream.  Enums,
-   * groups, and embedded messages are not handled by this method.
+   * Read a field of any primitive type for immutable messages from a
+   * CodedInputStream. Enums, groups, and embedded messages are not handled by
+   * this method.
    *
    * @param input The stream from which to read.
    * @param type Declared type of the field.
+   * @param checkUtf8 When true, check that the input is valid utf8.
    * @return An object representing the field's value, of the exact
    *         type which would be returned by
    *         {@link Message#getField(Descriptors.FieldDescriptor)} for
@@ -536,7 +551,8 @@ final class FieldSet<FieldDescriptorType extends
    */
   public static Object readPrimitiveField(
       CodedInputStream input,
-      final WireFormat.FieldType type) throws IOException {
+      final WireFormat.FieldType type,
+      boolean checkUtf8) throws IOException {
     switch (type) {
       case DOUBLE  : return input.readDouble  ();
       case FLOAT   : return input.readFloat   ();
@@ -546,7 +562,11 @@ final class FieldSet<FieldDescriptorType extends
       case FIXED64 : return input.readFixed64 ();
       case FIXED32 : return input.readFixed32 ();
       case BOOL    : return input.readBool    ();
-      case STRING  : return input.readString  ();
+      case STRING  : if (checkUtf8) {
+                       return input.readStringRequireUtf8();
+                     } else {
+                       return input.readString();
+                     }
       case BYTES   : return input.readBytes   ();
       case UINT32  : return input.readUInt32  ();
       case SFIXED32: return input.readSFixed32();
@@ -571,6 +591,7 @@ final class FieldSet<FieldDescriptorType extends
       "There is no way to get here, but the compiler thinks otherwise.");
   }
 
+
   /** See {@link Message#writeTo(CodedOutputStream)}. */
   public void writeTo(final CodedOutputStream output)
                       throws IOException {
@@ -605,8 +626,12 @@ final class FieldSet<FieldDescriptorType extends
     final FieldDescriptorType descriptor = entry.getKey();
     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
         !descriptor.isRepeated() && !descriptor.isPacked()) {
+      Object value = entry.getValue();
+      if (value instanceof LazyField) {
+        value = ((LazyField) value).getValue();
+      }
       output.writeMessageSetExtension(entry.getKey().getNumber(),
-                                      (MessageLite) entry.getValue());
+                                      (MessageLite) value);
     } else {
       writeField(descriptor, entry.getValue(), output);
     }
@@ -630,7 +655,7 @@ final class FieldSet<FieldDescriptorType extends
     // Special case for groups, which need a start and end tag; other fields
     // can just use writeTag() and writeFieldNoTag().
     if (type == WireFormat.FieldType.GROUP) {
-      output.writeGroup(number, (MessageLite) value);
+        output.writeGroup(number, (MessageLite) value);
     } else {
       output.writeTag(number, getWireFormatForFieldType(type, false));
       writeElementNoTag(output, type, value);
@@ -663,7 +688,13 @@ final class FieldSet<FieldDescriptorType extends
       case STRING  : output.writeStringNoTag  ((String     ) value); break;
       case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
       case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
-      case BYTES   : output.writeBytesNoTag   ((ByteString ) value); break;
+      case BYTES:
+        if (value instanceof ByteString) {
+          output.writeBytesNoTag((ByteString) value);
+        } else {
+          output.writeByteArrayNoTag((byte[]) value);
+        }
+        break;
       case UINT32  : output.writeUInt32NoTag  ((Integer    ) value); break;
       case SFIXED32: output.writeSFixed32NoTag((Integer    ) value); break;
       case SFIXED64: output.writeSFixed64NoTag((Long       ) value); break;
@@ -671,7 +702,11 @@ final class FieldSet<FieldDescriptorType extends
       case SINT64  : output.writeSInt64NoTag  ((Long       ) value); break;
 
       case ENUM:
-        output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
+        if (value instanceof Internal.EnumLite) {
+          output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
+        } else {
+          output.writeEnumNoTag(((Integer) value).intValue());
+        }
         break;
     }
   }
@@ -778,7 +813,9 @@ final class FieldSet<FieldDescriptorType extends
       final int number, final Object value) {
     int tagSize = CodedOutputStream.computeTagSize(number);
     if (type == WireFormat.FieldType.GROUP) {
-      tagSize *= 2;
+      // Only count the end group tag for proto2 messages as for proto1 the end
+      // group tag will be counted as a part of getSerializedSize().
+        tagSize *= 2;
     }
     return tagSize + computeElementSizeNoTag(type, value);
   }
@@ -808,7 +845,12 @@ final class FieldSet<FieldDescriptorType extends
       case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
       case STRING  : return CodedOutputStream.computeStringSizeNoTag  ((String     )value);
       case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
-      case BYTES   : return CodedOutputStream.computeBytesSizeNoTag   ((ByteString )value);
+      case BYTES   :
+        if (value instanceof ByteString) {
+          return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+        } else {
+          return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
+        }
       case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
       case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
       case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
@@ -823,8 +865,12 @@ final class FieldSet<FieldDescriptorType extends
         }
 
       case ENUM:
-        return CodedOutputStream.computeEnumSizeNoTag(
-            ((Internal.EnumLite) value).getNumber());
+        if (value instanceof Internal.EnumLite) {
+          return CodedOutputStream.computeEnumSizeNoTag(
+              ((Internal.EnumLite) value).getNumber());
+        } else {
+          return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
+        }
     }
 
     throw new RuntimeException(

+ 331 - 57
java/src/main/java/com/google/protobuf/GeneratedMessage.java

@@ -33,6 +33,8 @@ package com.google.protobuf;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
 
 import java.io.IOException;
 import java.io.ObjectStreamException;
@@ -71,7 +73,7 @@ public abstract class GeneratedMessage extends AbstractMessage
   protected GeneratedMessage(Builder<?> builder) {
   }
 
-  public Parser<? extends Message> getParserForType() {
+  public Parser<? extends GeneratedMessage> getParserForType() {
     throw new UnsupportedOperationException(
         "This is supposed to be overridden by subclasses.");
   }
@@ -153,6 +155,16 @@ public abstract class GeneratedMessage extends AbstractMessage
     return Collections.unmodifiableMap(getAllFieldsMutable());
   }
 
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public boolean hasOneof(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+  }
+
   //@Override (Java 1.6 override semantics, but we must support 1.5)
   public boolean hasField(final FieldDescriptor field) {
     return internalGetFieldAccessorTable().getField(field).has(this);
@@ -193,6 +205,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     return unknownFields.mergeFieldFrom(tag, input);
   }
 
+
   /**
    * Used by parsing constructors in generated classes.
    */
@@ -344,6 +357,16 @@ public abstract class GeneratedMessage extends AbstractMessage
       return internalGetFieldAccessorTable().getField(field).getBuilder(this);
     }
 
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public boolean hasOneof(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+    }
+
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public boolean hasField(final FieldDescriptor field) {
       return internalGetFieldAccessorTable().getField(field).has(this);
@@ -373,6 +396,12 @@ public abstract class GeneratedMessage extends AbstractMessage
       return (BuilderType) this;
     }
 
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public BuilderType clearOneof(final OneofDescriptor oneof) {
+      internalGetFieldAccessorTable().getOneof(oneof).clear(this);
+      return (BuilderType) this;
+    }
+
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public int getRepeatedFieldCount(final FieldDescriptor field) {
       return internalGetFieldAccessorTable().getField(field)
@@ -507,21 +536,24 @@ public abstract class GeneratedMessage extends AbstractMessage
 
   public interface ExtendableMessageOrBuilder<
       MessageType extends ExtendableMessage> extends MessageOrBuilder {
+    // Re-define for return type covariance.
+    Message getDefaultInstanceForType();
 
     /** Check if a singular extension is present. */
     <Type> boolean hasExtension(
-        GeneratedExtension<MessageType, Type> extension);
+        Extension<MessageType, Type> extension);
 
     /** Get the number of elements in a repeated extension. */
     <Type> int getExtensionCount(
-        GeneratedExtension<MessageType, List<Type>> extension);
+        Extension<MessageType, List<Type>> extension);
 
     /** Get the value of an extension. */
-    <Type> Type getExtension(GeneratedExtension<MessageType, Type> extension);
+    <Type> Type getExtension(
+        Extension<MessageType, Type> extension);
 
     /** Get one element of a repeated extension. */
     <Type> Type getExtension(
-        GeneratedExtension<MessageType, List<Type>> extension,
+        Extension<MessageType, List<Type>> extension,
         int index);
   }
 
@@ -578,7 +610,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     }
 
     private void verifyExtensionContainingType(
-        final GeneratedExtension<MessageType, ?> extension) {
+        final Extension<MessageType, ?> extension) {
       if (extension.getDescriptor().getContainingType() !=
           getDescriptorForType()) {
         // This can only happen if someone uses unchecked operations.
@@ -593,7 +625,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     /** Check if a singular extension is present. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> boolean hasExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
+        final Extension<MessageType, Type> extension) {
       verifyExtensionContainingType(extension);
       return extensions.hasField(extension.getDescriptor());
     }
@@ -601,7 +633,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     /** Get the number of elements in a repeated extension. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> int getExtensionCount(
-        final GeneratedExtension<MessageType, List<Type>> extension) {
+        final Extension<MessageType, List<Type>> extension) {
       verifyExtensionContainingType(extension);
       final FieldDescriptor descriptor = extension.getDescriptor();
       return extensions.getRepeatedFieldCount(descriptor);
@@ -611,7 +643,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     @SuppressWarnings("unchecked")
     public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
+        final Extension<MessageType, Type> extension) {
       verifyExtensionContainingType(extension);
       FieldDescriptor descriptor = extension.getDescriptor();
       final Object value = extensions.getField(descriptor);
@@ -634,7 +666,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     @SuppressWarnings("unchecked")
     public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
+        final Extension<MessageType, List<Type>> extension,
         final int index) {
       verifyExtensionContainingType(extension);
       FieldDescriptor descriptor = extension.getDescriptor();
@@ -658,11 +690,12 @@ public abstract class GeneratedMessage extends AbstractMessage
         UnknownFieldSet.Builder unknownFields,
         ExtensionRegistryLite extensionRegistry,
         int tag) throws IOException {
-      return AbstractMessage.Builder.mergeFieldFrom(
-        input, unknownFields, extensionRegistry, getDescriptorForType(),
-        null, extensions, tag);
+      return MessageReflection.mergeFieldFrom(
+          input, unknownFields, extensionRegistry, getDescriptorForType(),
+          new MessageReflection.ExtensionAdapter(extensions), tag);
     }
 
+
     /**
      * Used by parsing constructors in generated classes.
      */
@@ -868,6 +901,11 @@ public abstract class GeneratedMessage extends AbstractMessage
       super(parent);
     }
 
+    // For immutable message conversion.
+    void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
     @Override
     public BuilderType clear() {
       extensions = FieldSet.emptySet();
@@ -890,7 +928,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     }
 
     private void verifyExtensionContainingType(
-        final GeneratedExtension<MessageType, ?> extension) {
+        final Extension<MessageType, ?> extension) {
       if (extension.getDescriptor().getContainingType() !=
           getDescriptorForType()) {
         // This can only happen if someone uses unchecked operations.
@@ -905,7 +943,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     /** Check if a singular extension is present. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> boolean hasExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
+        final Extension<MessageType, Type> extension) {
       verifyExtensionContainingType(extension);
       return extensions.hasField(extension.getDescriptor());
     }
@@ -913,7 +951,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     /** Get the number of elements in a repeated extension. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> int getExtensionCount(
-        final GeneratedExtension<MessageType, List<Type>> extension) {
+        final Extension<MessageType, List<Type>> extension) {
       verifyExtensionContainingType(extension);
       final FieldDescriptor descriptor = extension.getDescriptor();
       return extensions.getRepeatedFieldCount(descriptor);
@@ -922,7 +960,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     /** Get the value of an extension. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
+        final Extension<MessageType, Type> extension) {
       verifyExtensionContainingType(extension);
       FieldDescriptor descriptor = extension.getDescriptor();
       final Object value = extensions.getField(descriptor);
@@ -944,7 +982,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     /** Get one element of a repeated extension. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
+        final Extension<MessageType, List<Type>> extension,
         final int index) {
       verifyExtensionContainingType(extension);
       FieldDescriptor descriptor = extension.getDescriptor();
@@ -954,7 +992,7 @@ public abstract class GeneratedMessage extends AbstractMessage
 
     /** Set the value of an extension. */
     public final <Type> BuilderType setExtension(
-        final GeneratedExtension<MessageType, Type> extension,
+        final Extension<MessageType, Type> extension,
         final Type value) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
@@ -966,7 +1004,7 @@ public abstract class GeneratedMessage extends AbstractMessage
 
     /** Set the value of one element of a repeated extension. */
     public final <Type> BuilderType setExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
+        final Extension<MessageType, List<Type>> extension,
         final int index, final Type value) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
@@ -980,7 +1018,7 @@ public abstract class GeneratedMessage extends AbstractMessage
 
     /** Append a value to a repeated extension. */
     public final <Type> BuilderType addExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
+        final Extension<MessageType, List<Type>> extension,
         final Type value) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
@@ -993,7 +1031,7 @@ public abstract class GeneratedMessage extends AbstractMessage
 
     /** Clear an extension. */
     public final <Type> BuilderType clearExtension(
-        final GeneratedExtension<MessageType, ?> extension) {
+        final Extension<MessageType, ?> extension) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
       extensions.clearField(extension.getDescriptor());
@@ -1030,9 +1068,9 @@ public abstract class GeneratedMessage extends AbstractMessage
         final UnknownFieldSet.Builder unknownFields,
         final ExtensionRegistryLite extensionRegistry,
         final int tag) throws IOException {
-      return AbstractMessage.Builder.mergeFieldFrom(
-        input, unknownFields, extensionRegistry, getDescriptorForType(),
-        this, null, tag);
+      return MessageReflection.mergeFieldFrom(
+          input, unknownFields, extensionRegistry, getDescriptorForType(),
+          new MessageReflection.BuilderAdapter(this), tag);
     }
 
     // ---------------------------------------------------------------
@@ -1172,7 +1210,7 @@ public abstract class GeneratedMessage extends AbstractMessage
    * Gets the descriptor for an extension. The implementation depends on whether
    * the extension is scoped in the top level of a file or scoped in a Message.
    */
-  private static interface ExtensionDescriptorRetriever {
+  static interface ExtensionDescriptorRetriever {
     FieldDescriptor getDescriptor();
   }
 
@@ -1187,15 +1225,16 @@ public abstract class GeneratedMessage extends AbstractMessage
     // the outer class's descriptor, from which the extension descriptor is
     // obtained.
     return new GeneratedExtension<ContainingType, Type>(
-        new ExtensionDescriptorRetriever() {
+        new CachedDescriptorRetriever() {
           //@Override (Java 1.6 override semantics, but we must support 1.5)
-          public FieldDescriptor getDescriptor() {
+          public FieldDescriptor loadDescriptor() {
             return scope.getDescriptorForType().getExtensions()
                 .get(descriptorIndex);
           }
         },
         singularType,
-        defaultInstance);
+        defaultInstance,
+        Extension.ExtensionType.IMMUTABLE);
   }
 
   /** For use by generated code only. */
@@ -1209,7 +1248,87 @@ public abstract class GeneratedMessage extends AbstractMessage
     return new GeneratedExtension<ContainingType, Type>(
         null,  // ExtensionDescriptorRetriever is initialized in internalInit();
         singularType,
-        defaultInstance);
+        defaultInstance,
+        Extension.ExtensionType.IMMUTABLE);
+  }
+
+  private abstract static class CachedDescriptorRetriever
+      implements ExtensionDescriptorRetriever {
+    private volatile FieldDescriptor descriptor;
+    protected abstract FieldDescriptor loadDescriptor();
+    
+    public FieldDescriptor getDescriptor() {
+      if (descriptor == null) {
+        synchronized (this) {
+          if (descriptor == null) {
+            descriptor = loadDescriptor();
+          }
+        }
+      }
+      return descriptor;
+    }
+  }
+
+  /**
+   * Used in proto1 generated code only.
+   *
+   * After enabling bridge, we can define proto2 extensions (the extended type
+   * is a proto2 mutable message) in a proto1 .proto file. For these extensions
+   * we should generate proto2 GeneratedExtensions.
+   */
+  public static <ContainingType extends Message, Type>
+      GeneratedExtension<ContainingType, Type>
+      newMessageScopedGeneratedExtension(
+          final Message scope, final String name,
+          final Class singularType, final Message defaultInstance) {
+    // For extensions scoped within a Message, we use the Message to resolve
+    // the outer class's descriptor, from which the extension descriptor is
+    // obtained.
+    return new GeneratedExtension<ContainingType, Type>(
+        new CachedDescriptorRetriever() {
+          protected FieldDescriptor loadDescriptor() {
+            return scope.getDescriptorForType().findFieldByName(name);
+          }
+        },
+        singularType,
+        defaultInstance,
+        Extension.ExtensionType.MUTABLE);
+  }
+
+  /**
+   * Used in proto1 generated code only.
+   *
+   * After enabling bridge, we can define proto2 extensions (the extended type
+   * is a proto2 mutable message) in a proto1 .proto file. For these extensions
+   * we should generate proto2 GeneratedExtensions.
+   */
+  public static <ContainingType extends Message, Type>
+     GeneratedExtension<ContainingType, Type>
+     newFileScopedGeneratedExtension(
+         final Class singularType, final Message defaultInstance,
+         final String descriptorOuterClass, final String extensionName) {
+    // For extensions scoped within a file, we load the descriptor outer
+    // class and rely on it to get the FileDescriptor which then can be
+    // used to obtain the extension's FieldDescriptor.
+    return new GeneratedExtension<ContainingType, Type>(
+        new CachedDescriptorRetriever() {
+          protected FieldDescriptor loadDescriptor() {
+            try {
+              Class clazz =
+                  singularType.getClassLoader().loadClass(descriptorOuterClass);
+              FileDescriptor file =
+                  (FileDescriptor) clazz.getField("descriptor").get(null);
+              return file.findExtensionByName(extensionName);
+            } catch (Exception e) {
+              throw new RuntimeException(
+                  "Cannot load descriptors: " + descriptorOuterClass +
+                  " is not a valid descriptor class name", e);
+            }
+          }
+        },
+        singularType,
+        defaultInstance,
+        Extension.ExtensionType.MUTABLE);
   }
 
   /**
@@ -1237,8 +1356,9 @@ public abstract class GeneratedMessage extends AbstractMessage
    * these static singletons as parameters to the extension accessors defined
    * in {@link ExtendableMessage} and {@link ExtendableBuilder}.
    */
-  public static final class GeneratedExtension<
-      ContainingType extends Message, Type> {
+  public static class GeneratedExtension<
+      ContainingType extends Message, Type> extends
+      Extension<ContainingType, Type> {
     // TODO(kenton):  Find ways to avoid using Java reflection within this
     //   class.  Also try to avoid suppressing unchecked warnings.
 
@@ -1254,9 +1374,10 @@ public abstract class GeneratedMessage extends AbstractMessage
     // In the case of non-nested extensions, we initialize the
     // ExtensionDescriptorRetriever to null and rely on the outer class's static
     // initializer to call internalInit() after the descriptor has been parsed.
-    private GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
-                               Class singularType,
-                               Message messageDefaultInstance) {
+    GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
+        Class singularType,
+        Message messageDefaultInstance,
+        ExtensionType extensionType) {
       if (Message.class.isAssignableFrom(singularType) &&
           !singularType.isInstance(messageDefaultInstance)) {
         throw new IllegalArgumentException(
@@ -1275,6 +1396,7 @@ public abstract class GeneratedMessage extends AbstractMessage
         this.enumValueOf = null;
         this.enumGetValueDescriptor = null;
       }
+      this.extensionType = extensionType;
     }
 
     /** For use by generated code only. */
@@ -1295,6 +1417,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     private final Message messageDefaultInstance;
     private final Method enumValueOf;
     private final Method enumGetValueDescriptor;
+    private final ExtensionType extensionType;
 
     public FieldDescriptor getDescriptor() {
       if (descriptorRetriever == null) {
@@ -1312,14 +1435,19 @@ public abstract class GeneratedMessage extends AbstractMessage
       return messageDefaultInstance;
     }
 
+    protected ExtensionType getExtensionType() {
+      return extensionType;
+    }
+
     /**
      * Convert from the type used by the reflection accessors to the type used
      * by native accessors.  E.g., for enums, the reflection accessors use
      * EnumValueDescriptors but the native accessors use the generated enum
      * type.
      */
+    // @Override
     @SuppressWarnings("unchecked")
-    private Object fromReflectionType(final Object value) {
+    protected Object fromReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
       if (descriptor.isRepeated()) {
         if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
@@ -1342,21 +1470,16 @@ public abstract class GeneratedMessage extends AbstractMessage
      * Like {@link #fromReflectionType(Object)}, but if the type is a repeated
      * type, this converts a single element.
      */
-    private Object singularFromReflectionType(final Object value) {
+    // @Override
+    protected Object singularFromReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
       switch (descriptor.getJavaType()) {
         case MESSAGE:
           if (singularType.isInstance(value)) {
             return value;
           } else {
-            // It seems the copy of the embedded message stored inside the
-            // extended message is not of the exact type the user was
-            // expecting.  This can happen if a user defines a
-            // GeneratedExtension manually and gives it a different type.
-            // This should not happen in normal use.  But, to be nice, we'll
-            // copy the message to whatever type the caller was expecting.
             return messageDefaultInstance.newBuilderForType()
-                           .mergeFrom((Message) value).build();
+                .mergeFrom((Message) value).build();
           }
         case ENUM:
           return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
@@ -1371,8 +1494,9 @@ public abstract class GeneratedMessage extends AbstractMessage
      * EnumValueDescriptors but the native accessors use the generated enum
      * type.
      */
+    // @Override
     @SuppressWarnings("unchecked")
-    private Object toReflectionType(final Object value) {
+    protected Object toReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
       if (descriptor.isRepeated()) {
         if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
@@ -1394,7 +1518,8 @@ public abstract class GeneratedMessage extends AbstractMessage
      * Like {@link #toReflectionType(Object)}, but if the type is a repeated
      * type, this converts a single element.
      */
-    private Object singularToReflectionType(final Object value) {
+    // @Override
+    protected Object singularToReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
       switch (descriptor.getJavaType()) {
         case ENUM:
@@ -1403,6 +1528,34 @@ public abstract class GeneratedMessage extends AbstractMessage
           return value;
       }
     }
+
+    // @Override
+    public int getNumber() {
+      return getDescriptor().getNumber();
+    }
+
+    // @Override
+    public WireFormat.FieldType getLiteType() {
+      return getDescriptor().getLiteType();
+    }
+
+    // @Override
+    public boolean isRepeated() {
+      return getDescriptor().isRepeated();
+    }
+
+    // @Override
+    @SuppressWarnings("unchecked")
+    public Type getDefaultValue() {
+      if (isRepeated()) {
+        return (Type) Collections.emptyList();
+      }
+      if (getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        return (Type) messageDefaultInstance;
+      }
+      return (Type) singularFromReflectionType(
+          getDescriptor().getDefaultValue());
+    }
   }
 
   // =================================================================
@@ -1477,6 +1630,7 @@ public abstract class GeneratedMessage extends AbstractMessage
       this.descriptor = descriptor;
       this.camelCaseNames = camelCaseNames;
       fields = new FieldAccessor[descriptor.getFields().size()];
+      oneofs = new OneofAccessor[descriptor.getOneofs().size()];
       initialized = false;
     }
 
@@ -1493,8 +1647,14 @@ public abstract class GeneratedMessage extends AbstractMessage
       if (initialized) { return this; }
       synchronized (this) {
         if (initialized) { return this; }
-        for (int i = 0; i < fields.length; i++) {
+        int fieldsSize = fields.length;
+        for (int i = 0; i < fieldsSize; i++) {
           FieldDescriptor field = descriptor.getFields().get(i);
+          String containingOneofCamelCaseName = null;
+          if (field.getContainingOneof() != null) {
+            containingOneofCamelCaseName =
+                camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
+          }
           if (field.isRepeated()) {
             if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
               fields[i] = new RepeatedMessageFieldAccessor(
@@ -1509,16 +1669,26 @@ public abstract class GeneratedMessage extends AbstractMessage
           } else {
             if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
               fields[i] = new SingularMessageFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass);
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
             } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
               fields[i] = new SingularEnumFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass);
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
             } else {
               fields[i] = new SingularFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass);
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
             }
           }
         }
+
+        int oneofsSize = oneofs.length;
+        for (int i = 0; i < oneofsSize; i++) {
+          oneofs[i] = new OneofAccessor(
+              descriptor, camelCaseNames[i + fieldsSize],
+              messageClass, builderClass);
+        }
         initialized = true;
         camelCaseNames = null;
         return this;
@@ -1528,6 +1698,7 @@ public abstract class GeneratedMessage extends AbstractMessage
     private final Descriptor descriptor;
     private final FieldAccessor[] fields;
     private String[] camelCaseNames;
+    private final OneofAccessor[] oneofs;
     private volatile boolean initialized;
 
     /** Get the FieldAccessor for a particular field. */
@@ -1544,6 +1715,15 @@ public abstract class GeneratedMessage extends AbstractMessage
       return fields[field.getIndex()];
     }
 
+    /** Get the OneofAccessor for a particular oneof. */
+    private OneofAccessor getOneof(final OneofDescriptor oneof) {
+      if (oneof.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "OneofDescriptor does not match message type.");
+      }
+      return oneofs[oneof.getIndex()];
+    }
+
     /**
      * Abstract interface that provides access to a single field.  This is
      * implemented differently depending on the field type and cardinality.
@@ -1566,22 +1746,89 @@ public abstract class GeneratedMessage extends AbstractMessage
       Message.Builder getBuilder(GeneratedMessage.Builder builder);
     }
 
+    /** OneofAccessor provides access to a single oneof. */
+    private static class OneofAccessor {
+      OneofAccessor(
+          final Descriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass) {
+        this.descriptor = descriptor;
+        caseMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
+        caseMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      private final Descriptor descriptor;
+      private final Method caseMethod;
+      private final Method caseMethodBuilder;
+      private final Method clearMethod;
+
+      public boolean has(final GeneratedMessage message) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public boolean has(GeneratedMessage.Builder builder) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public FieldDescriptor get(final GeneratedMessage message) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public FieldDescriptor get(GeneratedMessage.Builder builder) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+    }
+    
+    private static boolean supportFieldPresence(FileDescriptor file) {
+      return true;
+    }
+
     // ---------------------------------------------------------------
 
     private static class SingularFieldAccessor implements FieldAccessor {
       SingularFieldAccessor(
           final FieldDescriptor descriptor, final String camelCaseName,
           final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        field = descriptor;
+        isOneofField = descriptor.getContainingOneof() != null;
+        hasHasMethod = supportFieldPresence(descriptor.getFile())
+            || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
         getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
         getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
         type = getMethod.getReturnType();
         setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
         hasMethod =
-            getMethodOrDie(messageClass, "has" + camelCaseName);
+            hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
         hasMethodBuilder =
-            getMethodOrDie(builderClass, "has" + camelCaseName);
+            hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
         clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+        caseMethod = isOneofField ? getMethodOrDie(
+            messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
+        caseMethodBuilder = isOneofField ? getMethodOrDie(
+            builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
       }
 
       // Note:  We use Java reflection to call public methods rather than
@@ -1594,6 +1841,19 @@ public abstract class GeneratedMessage extends AbstractMessage
       protected final Method hasMethod;
       protected final Method hasMethodBuilder;
       protected final Method clearMethod;
+      protected final Method caseMethod;
+      protected final Method caseMethodBuilder;
+      protected final FieldDescriptor field;
+      protected final boolean isOneofField;
+      protected final boolean hasHasMethod;
+      
+      private int getOneofFieldNumber(final GeneratedMessage message) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+      }
+      
+      private int getOneofFieldNumber(final GeneratedMessage.Builder builder) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+      }
 
       public Object get(final GeneratedMessage message) {
         return invokeOrDie(getMethod, message);
@@ -1623,9 +1883,21 @@ public abstract class GeneratedMessage extends AbstractMessage
           "addRepeatedField() called on a singular field.");
       }
       public boolean has(final GeneratedMessage message) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(message) == field.getNumber();
+          }
+          return !get(message).equals(field.getDefaultValue());
+        }
         return (Boolean) invokeOrDie(hasMethod, message);
       }
       public boolean has(GeneratedMessage.Builder builder) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(builder) == field.getNumber();
+          }
+          return !get(builder).equals(field.getDefaultValue());
+        }
         return (Boolean) invokeOrDie(hasMethodBuilder, builder);
       }
       public int getRepeatedCount(final GeneratedMessage message) {
@@ -1751,8 +2023,9 @@ public abstract class GeneratedMessage extends AbstractMessage
       SingularEnumFieldAccessor(
           final FieldDescriptor descriptor, final String camelCaseName,
           final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
-        super(descriptor, camelCaseName, messageClass, builderClass);
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
 
         valueOfMethod = getMethodOrDie(type, "valueOf",
                                        EnumValueDescriptor.class);
@@ -1847,8 +2120,9 @@ public abstract class GeneratedMessage extends AbstractMessage
       SingularMessageFieldAccessor(
           final FieldDescriptor descriptor, final String camelCaseName,
           final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
-        super(descriptor, camelCaseName, messageClass, builderClass);
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
 
         newBuilderMethod = getMethodOrDie(type, "newBuilder");
         getBuilderMethodBuilder =

+ 190 - 38
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -35,6 +35,7 @@ import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -66,9 +67,10 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
    */
   protected boolean parseUnknownField(
       CodedInputStream input,
+      CodedOutputStream unknownFieldsCodedOutput,
       ExtensionRegistryLite extensionRegistry,
       int tag) throws IOException {
-    return input.skipField(tag);
+    return input.skipField(tag, unknownFieldsCodedOutput);
   }
 
   /**
@@ -86,6 +88,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
 
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public BuilderType clear() {
+      unknownFields = ByteString.EMPTY;
       return (BuilderType) this;
     }
 
@@ -110,12 +113,25 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
      */
     protected boolean parseUnknownField(
         CodedInputStream input,
+        CodedOutputStream unknownFieldsCodedOutput,
         ExtensionRegistryLite extensionRegistry,
         int tag) throws IOException {
-      return input.skipField(tag);
+      return input.skipField(tag, unknownFieldsCodedOutput);
     }
+
+    public final ByteString getUnknownFields() {
+      return unknownFields;
+    }
+
+    public final BuilderType setUnknownFields(final ByteString unknownFields) {
+      this.unknownFields = unknownFields;
+      return (BuilderType) this;
+    }
+
+    private ByteString unknownFields = ByteString.EMPTY;
   }
 
+
   // =================================================================
   // Extensions-related stuff
 
@@ -197,7 +213,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       if (value == null) {
         return extension.defaultValue;
       } else {
-        return (Type) value;
+        return (Type) extension.fromFieldSetType(value);
       }
     }
 
@@ -208,7 +224,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
         final GeneratedExtension<MessageType, List<Type>> extension,
         final int index) {
       verifyExtensionContainingType(extension);
-      return (Type) extensions.getRepeatedField(extension.descriptor, index);
+      return (Type) extension.singularFromFieldSetType(
+          extensions.getRepeatedField(extension.descriptor, index));
     }
 
     /** Called by subclasses to check if all extensions are initialized. */
@@ -223,16 +240,19 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     @Override
     protected boolean parseUnknownField(
         CodedInputStream input,
+        CodedOutputStream unknownFieldsCodedOutput,
         ExtensionRegistryLite extensionRegistry,
         int tag) throws IOException {
       return GeneratedMessageLite.parseUnknownField(
           extensions,
           getDefaultInstanceForType(),
           input,
+          unknownFieldsCodedOutput,
           extensionRegistry,
           tag);
     }
 
+
     /**
      * Used by parsing constructors in generated classes.
      */
@@ -314,6 +334,11 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
     private boolean extensionsIsMutable;
 
+    // For immutable message conversion.
+    void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
     @Override
     public BuilderType clear() {
       extensions.clear();
@@ -375,7 +400,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       if (value == null) {
         return extension.defaultValue;
       } else {
-        return (Type) value;
+        return (Type) extension.fromFieldSetType(value);
       }
     }
 
@@ -386,7 +411,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
         final GeneratedExtension<MessageType, List<Type>> extension,
         final int index) {
       verifyExtensionContainingType(extension);
-      return (Type) extensions.getRepeatedField(extension.descriptor, index);
+      return (Type) extension.singularFromFieldSetType(
+          extensions.getRepeatedField(extension.descriptor, index));
     }
 
     // This is implemented here only to work around an apparent bug in the
@@ -404,7 +430,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
         final Type value) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
-      extensions.setField(extension.descriptor, value);
+      extensions.setField(extension.descriptor,
+                          extension.toFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -414,7 +441,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
         final int index, final Type value) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
-      extensions.setRepeatedField(extension.descriptor, index, value);
+      extensions.setRepeatedField(extension.descriptor, index,
+                                  extension.singularToFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -424,7 +452,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
         final Type value) {
       verifyExtensionContainingType(extension);
       ensureExtensionsIsMutable();
-      extensions.addRepeatedField(extension.descriptor, value);
+      extensions.addRepeatedField(extension.descriptor,
+                                  extension.singularToFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -449,6 +478,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     @Override
     protected boolean parseUnknownField(
         CodedInputStream input,
+        CodedOutputStream unknownFieldsCodedOutput,
         ExtensionRegistryLite extensionRegistry,
         int tag) throws IOException {
       ensureExtensionsIsMutable();
@@ -456,6 +486,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
           extensions,
           getDefaultInstanceForType(),
           input,
+          unknownFieldsCodedOutput,
           extensionRegistry,
           tag);
     }
@@ -477,6 +508,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
           FieldSet<ExtensionDescriptor> extensions,
           MessageType defaultInstance,
           CodedInputStream input,
+          CodedOutputStream unknownFieldsCodedOutput,
           ExtensionRegistryLite extensionRegistry,
           int tag) throws IOException {
     int wireType = WireFormat.getTagWireType(tag);
@@ -505,7 +537,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     }
 
     if (unknown) {  // Unknown field or wrong wire type.  Skip.
-      return input.skipField(tag);
+      return input.skipField(tag, unknownFieldsCodedOutput);
     }
 
     if (packed) {
@@ -521,13 +553,15 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
             // enum, drop it (don't even add it to unknownFields).
             return true;
           }
-          extensions.addRepeatedField(extension.descriptor, value);
+          extensions.addRepeatedField(extension.descriptor,
+                                      extension.singularToFieldSetType(value));
         }
       } else {
         while (input.getBytesUntilLimit() > 0) {
           Object value =
-            FieldSet.readPrimitiveField(input,
-                                        extension.descriptor.getLiteType());
+              FieldSet.readPrimitiveField(input,
+                                          extension.descriptor.getLiteType(),
+                                          /*checkUtf8=*/ false);
           extensions.addRepeatedField(extension.descriptor, value);
         }
       }
@@ -545,7 +579,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
             }
           }
           if (subBuilder == null) {
-            subBuilder = extension.messageDefaultInstance.newBuilderForType();
+            subBuilder = extension.getMessageDefaultInstance()
+                .newBuilderForType();
           }
           if (extension.descriptor.getLiteType() ==
               WireFormat.FieldType.GROUP) {
@@ -562,21 +597,26 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
           value = extension.descriptor.getEnumType()
                            .findValueByNumber(rawValue);
           // If the number isn't recognized as a valid value for this enum,
-          // drop it.
+          // write it to unknown fields object.
           if (value == null) {
+            unknownFieldsCodedOutput.writeRawVarint32(tag);
+            unknownFieldsCodedOutput.writeUInt32NoTag(rawValue);
             return true;
           }
           break;
         default:
           value = FieldSet.readPrimitiveField(input,
-              extension.descriptor.getLiteType());
+              extension.descriptor.getLiteType(),
+              /*checkUtf8=*/ false);
           break;
       }
 
       if (extension.descriptor.isRepeated()) {
-        extensions.addRepeatedField(extension.descriptor, value);
+        extensions.addRepeatedField(extension.descriptor,
+                                    extension.singularToFieldSetType(value));
       } else {
-        extensions.setField(extension.descriptor, value);
+        extensions.setField(extension.descriptor,
+                            extension.singularToFieldSetType(value));
       }
     }
 
@@ -594,14 +634,16 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
               final MessageLite messageDefaultInstance,
               final Internal.EnumLiteMap<?> enumTypeMap,
               final int number,
-              final WireFormat.FieldType type) {
+              final WireFormat.FieldType type,
+              final Class singularType) {
     return new GeneratedExtension<ContainingType, Type>(
         containingTypeDefaultInstance,
         defaultValue,
         messageDefaultInstance,
         new ExtensionDescriptor(enumTypeMap, number, type,
                                 false /* isRepeated */,
-                                false /* isPacked */));
+                                false /* isPacked */),
+        singularType);
   }
 
   /** For use by generated code only. */
@@ -613,7 +655,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
               final Internal.EnumLiteMap<?> enumTypeMap,
               final int number,
               final WireFormat.FieldType type,
-              final boolean isPacked) {
+              final boolean isPacked,
+              final Class singularType) {
     @SuppressWarnings("unchecked")  // Subclasses ensure Type is a List
     Type emptyList = (Type) Collections.emptyList();
     return new GeneratedExtension<ContainingType, Type>(
@@ -621,13 +664,14 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
         emptyList,
         messageDefaultInstance,
         new ExtensionDescriptor(
-            enumTypeMap, number, type, true /* isRepeated */, isPacked));
+            enumTypeMap, number, type, true /* isRepeated */, isPacked),
+        singularType);
   }
 
-  private static final class ExtensionDescriptor
+  static final class ExtensionDescriptor
       implements FieldSet.FieldDescriptorLite<
         ExtensionDescriptor> {
-    private ExtensionDescriptor(
+    ExtensionDescriptor(
         final Internal.EnumLiteMap<?> enumTypeMap,
         final int number,
         final WireFormat.FieldType type,
@@ -640,11 +684,11 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       this.isPacked = isPacked;
     }
 
-    private final Internal.EnumLiteMap<?> enumTypeMap;
-    private final int number;
-    private final WireFormat.FieldType type;
-    private final boolean isRepeated;
-    private final boolean isPacked;
+    final Internal.EnumLiteMap<?> enumTypeMap;
+    final int number;
+    final WireFormat.FieldType type;
+    final boolean isRepeated;
+    final boolean isPacked;
 
     public int getNumber() {
       return number;
@@ -676,25 +720,70 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
     }
 
+
     public int compareTo(ExtensionDescriptor other) {
       return number - other.number;
     }
   }
 
+  // =================================================================
+
+  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+  @SuppressWarnings("unchecked")
+  static Method getMethodOrDie(Class clazz, String name, Class... params) {
+    try {
+      return clazz.getMethod(name, params);
+    } catch (NoSuchMethodException e) {
+      throw new RuntimeException(
+        "Generated message class \"" + clazz.getName() +
+        "\" missing method \"" + name + "\".", e);
+    }
+  }
+
+  /** Calls invoke and throws a RuntimeException if it fails. */
+  static Object invokeOrDie(Method method, Object object, Object... params) {
+    try {
+      return method.invoke(object, params);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(
+        "Couldn't use Java reflection to implement protocol message " +
+        "reflection.", e);
+    } catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof RuntimeException) {
+        throw (RuntimeException) cause;
+      } else if (cause instanceof Error) {
+        throw (Error) cause;
+      } else {
+        throw new RuntimeException(
+          "Unexpected exception thrown by generated accessor method.", cause);
+      }
+    }
+  }
+
   /**
    * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
    *
    * Users should ignore the contents of this class and only use objects of
    * this type as parameters to extension accessors and ExtensionRegistry.add().
    */
-  public static final class GeneratedExtension<
+  public static class GeneratedExtension<
       ContainingType extends MessageLite, Type> {
 
-    private GeneratedExtension(
+    /**
+     * Create a new isntance with the given parameters.
+     *
+     * The last parameter {@code singularType} is only needed for enum types.
+     * We store integer values for enum types in a {@link ExtendableMessage}
+     * and use Java reflection to convert an integer value back into a concrete
+     * enum object.
+     */
+    GeneratedExtension(
         final ContainingType containingTypeDefaultInstance,
         final Type defaultValue,
         final MessageLite messageDefaultInstance,
-        final ExtensionDescriptor descriptor) {
+        final ExtensionDescriptor descriptor,
+        Class singularType) {
       // Defensive checks to verify the correct initialization order of
       // GeneratedExtensions and their related GeneratedMessages.
       if (containingTypeDefaultInstance == null) {
@@ -710,12 +799,24 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       this.defaultValue = defaultValue;
       this.messageDefaultInstance = messageDefaultInstance;
       this.descriptor = descriptor;
+
+      // Use Java reflection to invoke the static method {@code valueOf} of
+      // enum types in order to convert integers to concrete enum objects.
+      this.singularType = singularType;
+      if (Internal.EnumLite.class.isAssignableFrom(singularType)) {
+        this.enumValueOf = getMethodOrDie(
+            singularType, "valueOf", int.class);
+      } else {
+        this.enumValueOf = null;
+      }
     }
 
-    private final ContainingType containingTypeDefaultInstance;
-    private final Type defaultValue;
-    private final MessageLite messageDefaultInstance;
-    private final ExtensionDescriptor descriptor;
+    final ContainingType containingTypeDefaultInstance;
+    final Type defaultValue;
+    final MessageLite messageDefaultInstance;
+    final ExtensionDescriptor descriptor;
+    final Class singularType;
+    final Method enumValueOf;
 
     /**
      * Default instance of the type being extended, used to identify that type.
@@ -729,13 +830,64 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       return descriptor.getNumber();
     }
 
+
     /**
-     * If the extension is an embedded message, this is the default instance of
-     * that type.
+     * If the extension is an embedded message or group, returns the default
+     * instance of the message.
      */
     public MessageLite getMessageDefaultInstance() {
       return messageDefaultInstance;
     }
+
+    @SuppressWarnings("unchecked")
+    Object fromFieldSetType(final Object value) {
+      if (descriptor.isRepeated()) {
+        if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+          final List result = new ArrayList();
+          for (final Object element : (List) value) {
+            result.add(singularFromFieldSetType(element));
+          }
+          return result;
+        } else {
+          return value;
+        }
+      } else {
+        return singularFromFieldSetType(value);
+      }
+    }
+
+    Object singularFromFieldSetType(final Object value) {
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+        return invokeOrDie(enumValueOf, null, (Integer) value);
+      } else {
+        return value;
+      }
+    }
+
+    @SuppressWarnings("unchecked")
+    Object toFieldSetType(final Object value) {
+      if (descriptor.isRepeated()) {
+        if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+          final List result = new ArrayList();
+          for (final Object element : (List) value) {
+            result.add(singularToFieldSetType(element));
+          }
+          return result;
+        } else {
+          return value;
+        }
+      } else {
+        return singularToFieldSetType(value);
+      }
+    }
+
+    Object singularToFieldSetType(final Object value) {
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+        return ((Internal.EnumLite) value).getNumber();
+      } else {
+        return value;
+      }
+    }
   }
 
   /**

+ 238 - 0
java/src/main/java/com/google/protobuf/Internal.java

@@ -30,7 +30,11 @@
 
 package com.google.protobuf;
 
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * The classes contained within are used internally by the Protocol Buffer
@@ -98,6 +102,51 @@ public class Internal {
           "Java VM does not support a standard character set.", e);
     }
   }
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is like {@link #bytesDefaultValue}, but returns a byte array. 
+   */
+  public static byte[] byteArrayDefaultValue(String bytes) {
+    try {
+      return bytes.getBytes("ISO-8859-1");
+    } catch (UnsupportedEncodingException e) {
+      // This should never happen since all JVMs are required to implement
+      // ISO-8859-1.
+      throw new IllegalStateException(
+          "Java VM does not support a standard character set.", e);
+    }
+  }
+
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is like {@link #bytesDefaultValue}, but returns a ByteBuffer. 
+   */
+  public static ByteBuffer byteBufferDefaultValue(String bytes) {
+    return ByteBuffer.wrap(byteArrayDefaultValue(bytes));
+  }
+
+  /**
+   * Create a new ByteBuffer and copy all the content of {@code source}
+   * ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and
+   * capacity will be source.capacity(), and its position will be 0.
+   * Note that the state of {@code source} ByteBuffer won't be changed.
+   */
+  public static ByteBuffer copyByteBuffer(ByteBuffer source) {
+    // Make a duplicate of the source ByteBuffer and read data from the
+    // duplicate. This is to avoid affecting the source ByteBuffer's state.
+    ByteBuffer temp = source.duplicate();
+    // We want to copy all the data in the source ByteBuffer, not just the
+    // remaining bytes.
+    temp.clear();
+    ByteBuffer result = ByteBuffer.allocate(temp.capacity());
+    result.put(temp);
+    result.clear();
+    return result;
+  }
 
   /**
    * Helper called by generated code to determine if a byte array is a valid
@@ -130,6 +179,35 @@ public class Internal {
   public static boolean isValidUtf8(ByteString byteString) {
     return byteString.isValidUtf8();
   }
+  
+  /**
+   * Like {@link #isValidUtf8(ByteString)} but for byte arrays.
+   */
+  public static boolean isValidUtf8(byte[] byteArray) {
+    return Utf8.isValidUtf8(byteArray);
+  }
+
+  /**
+   * Helper method to get the UTF-8 bytes of a string.
+   */
+  public static byte[] toByteArray(String value) {
+    try {
+      return value.getBytes("UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 not supported?", e);
+    }
+  }
+  
+  /**
+   * Helper method to convert a byte array to a string using UTF-8 encoding.
+   */
+  public static String toStringUtf8(byte[] bytes) {
+    try {
+      return new String(bytes, "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 not supported?", e);
+    }
+  }
 
   /**
    * Interface for an enum value or value descriptor, to be used in FieldSet.
@@ -150,4 +228,164 @@ public class Internal {
   public interface EnumLiteMap<T extends EnumLite> {
     T findValueByNumber(int number);
   }
+
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for longs.
+   * @see Long#hashCode()
+   */
+  public static int hashLong(long n) {
+    return (int) (n ^ (n >>> 32));
+  }
+
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for
+   * booleans.
+   * @see Boolean#hashCode()
+   */
+  public static int hashBoolean(boolean b) {
+    return b ? 1231 : 1237;
+  }
+
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for enums.
+   * <p>
+   * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
+   * need to use the field number as the hash code to ensure compatibility
+   * between statically and dynamically generated enum objects.
+   */
+  public static int hashEnum(EnumLite e) {
+    return e.getNumber();
+  }
+
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for
+   * enum lists.
+   */
+  public static int hashEnumList(List<? extends EnumLite> list) {
+    int hash = 1;
+    for (EnumLite e : list) {
+      hash = 31 * hash + hashEnum(e);
+    }
+    return hash;
+  }
+  
+  /**
+   * Helper method for implementing {@link MessageLite#equals()} for bytes field.
+   */
+  public static boolean equals(List<byte[]> a, List<byte[]> b) {
+    if (a.size() != b.size()) return false;
+    for (int i = 0; i < a.size(); ++i) {
+      if (!Arrays.equals(a.get(i), b.get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for bytes field.
+   */
+  public static int hashCode(List<byte[]> list) {
+    int hash = 1;
+    for (byte[] bytes : list) {
+      hash = 31 * hash + hashCode(bytes);
+    }
+    return hash;
+  }
+  
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for bytes field.
+   */
+  public static int hashCode(byte[] bytes) {
+    // The hash code for a byte array should be the same as the hash code for a
+    // ByteString with the same content. This is to ensure that the generated
+    // hashCode() method will return the same value as the pure reflection
+    // based hashCode() method.
+    return LiteralByteString.hashCode(bytes);
+  }
+  
+  /**
+   * Helper method for implementing {@link MessageLite#equals()} for bytes
+   * field.
+   */
+  public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) {
+    if (a.capacity() != b.capacity()) {
+      return false;
+    }
+    // ByteBuffer.equals() will only compare the remaining bytes, but we want to
+    // compare all the content.
+    return a.duplicate().clear().equals(b.duplicate().clear());
+  }
+  
+  /**
+   * Helper method for implementing {@link MessageLite#equals()} for bytes
+   * field.
+   */
+  public static boolean equalsByteBuffer(
+      List<ByteBuffer> a, List<ByteBuffer> b) {
+    if (a.size() != b.size()) {
+      return false;
+    }
+    for (int i = 0; i < a.size(); ++i) {
+      if (!equalsByteBuffer(a.get(i), b.get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for bytes
+   * field.
+   */
+  public static int hashCodeByteBuffer(List<ByteBuffer> list) {
+    int hash = 1;
+    for (ByteBuffer bytes : list) {
+      hash = 31 * hash + hashCodeByteBuffer(bytes);
+    }
+    return hash;
+  }
+  
+  private static final int DEFAULT_BUFFER_SIZE = 4096;
+  
+  /**
+   * Helper method for implementing {@link MessageLite#hashCode()} for bytes
+   * field.
+   */
+  public static int hashCodeByteBuffer(ByteBuffer bytes) {
+    if (bytes.hasArray()) {
+      // Fast path.
+      int h = LiteralByteString.hashCode(bytes.capacity(), bytes.array(),
+          bytes.arrayOffset(), bytes.capacity());
+      return h == 0 ? 1 : h;
+    } else {
+      // Read the data into a temporary byte array before calculating the
+      // hash value.
+      final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE
+          ? DEFAULT_BUFFER_SIZE : bytes.capacity();
+      final byte[] buffer = new byte[bufferSize];
+      final ByteBuffer duplicated = bytes.duplicate();
+      duplicated.clear();
+      int h = bytes.capacity();
+      while (duplicated.remaining() > 0) {
+        final int length = duplicated.remaining() <= bufferSize ?
+            duplicated.remaining() : bufferSize;
+        duplicated.get(buffer, 0, length);
+        h = LiteralByteString.hashCode(h, buffer, 0, length);
+      }
+      return h == 0 ? 1 : h;
+    }
+  }
+  
+  /**
+   * An empty byte array constant used in generated code.
+   */
+  public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+  
+  /**
+   * An empty byte array constant used in generated code.
+   */
+  public static final ByteBuffer EMPTY_BYTE_BUFFER =
+      ByteBuffer.wrap(EMPTY_BYTE_ARRAY);
+
 }

+ 8 - 0
java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java

@@ -111,4 +111,12 @@ public class InvalidProtocolBufferException extends IOException {
       "Protocol message was too large.  May be malicious.  " +
       "Use CodedInputStream.setSizeLimit() to increase the size limit.");
   }
+
+  static InvalidProtocolBufferException parseFailure() {
+    return new InvalidProtocolBufferException("Failed to parse the message.");
+  }
+
+  static InvalidProtocolBufferException invalidUtf8() {
+    return new InvalidProtocolBufferException("Protocol message had invalid UTF-8.");
+  }
 }

+ 25 - 81
java/src/main/java/com/google/protobuf/LazyField.java

@@ -30,7 +30,6 @@
 
 package com.google.protobuf;
 
-import java.io.IOException;
 import java.util.Iterator;
 import java.util.Map.Entry;
 
@@ -38,110 +37,49 @@ import java.util.Map.Entry;
  * LazyField encapsulates the logic of lazily parsing message fields. It stores
  * the message in a ByteString initially and then parse it on-demand.
  *
- * LazyField is thread-compatible e.g. concurrent read are safe, however,
- * synchronizations are needed under read/write situations.
- *
- * Now LazyField is only used to lazily load MessageSet.
- * TODO(xiangl): Use LazyField to lazily load all messages.
+ * Most of key methods are implemented in {@link LazyFieldLite} but this class
+ * can contain default instance of the message to provide {@code hashCode()},
+ * {@code euqals()} and {@code toString()}.
  *
  * @author xiangl@google.com (Xiang Li)
  */
-class LazyField {
-
-  final private MessageLite defaultInstance;
-  final private ExtensionRegistryLite extensionRegistry;
+public class LazyField extends LazyFieldLite {
 
-  // Mutable because it is initialized lazily.
-  private ByteString bytes;
-  private volatile MessageLite value;
-  private volatile boolean isDirty = false;
+  /**
+   * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
+   * {@code toString()}.
+   */
+  private final MessageLite defaultInstance;
 
   public LazyField(MessageLite defaultInstance,
       ExtensionRegistryLite extensionRegistry, ByteString bytes) {
-    this.defaultInstance = defaultInstance;
-    this.extensionRegistry = extensionRegistry;
-    this.bytes = bytes;
-  }
+    super(extensionRegistry, bytes);
 
-  public MessageLite getValue() {
-    ensureInitialized();
-    return value;
-  }
-
-  /**
-   * LazyField is not thread-safe for write access. Synchronizations are needed
-   * under read/write situations.
-   */
-  public MessageLite setValue(MessageLite value) {
-    MessageLite originalValue = this.value;
-    this.value = value;
-    bytes = null;
-    isDirty = true;
-    return originalValue;
+    this.defaultInstance = defaultInstance;
   }
 
-  /**
-   * Due to the optional field can be duplicated at the end of serialized
-   * bytes, which will make the serialized size changed after LazyField
-   * parsed. Be careful when using this method.
-   */
-  public int getSerializedSize() {
-    if (isDirty) {
-      return value.getSerializedSize();
-    }
-    return bytes.size();
+  @Override
+  public boolean containsDefaultInstance() {
+    return super.containsDefaultInstance() || value == defaultInstance;
   }
 
-  public ByteString toByteString() {
-    if (!isDirty) {
-      return bytes;
-    }
-    synchronized (this) {
-      if (!isDirty) {
-        return bytes;
-      }
-      bytes = value.toByteString();
-      isDirty = false;
-      return bytes;
-    }
+  public MessageLite getValue() {
+    return getValue(defaultInstance);
   }
 
   @Override
   public int hashCode() {
-    ensureInitialized();
-    return value.hashCode();
+    return getValue().hashCode();
   }
 
   @Override
   public boolean equals(Object obj) {
-    ensureInitialized();
-    return value.equals(obj);
+    return getValue().equals(obj);
   }
 
   @Override
   public String toString() {
-    ensureInitialized();
-    return value.toString();
-  }
-
-  private void ensureInitialized() {
-    if (value != null) {
-      return;
-    }
-    synchronized (this) {
-      if (value != null) {
-        return;
-      }
-      try {
-        if (bytes != null) {
-          value = defaultInstance.getParserForType()
-              .parseFrom(bytes, extensionRegistry);
-        }
-      } catch (IOException e) {
-        // TODO(xiangl): Refactory the API to support the exception thrown from
-        // lazily load messages.
-      }
-    }
+    return getValue().toString();
   }
 
   // ====================================================
@@ -157,10 +95,12 @@ class LazyField {
       this.entry = entry;
     }
 
+    // @Override
     public K getKey() {
       return entry.getKey();
     }
 
+    // @Override
     public Object getValue() {
       LazyField field = entry.getValue();
       if (field == null) {
@@ -173,6 +113,7 @@ class LazyField {
       return entry.getValue();
     }
 
+    // @Override
     public Object setValue(Object value) {
       if (!(value instanceof MessageLite)) {
         throw new IllegalArgumentException(
@@ -190,11 +131,13 @@ class LazyField {
       this.iterator = iterator;
     }
 
+    // @Override
     public boolean hasNext() {
       return iterator.hasNext();
     }
 
     @SuppressWarnings("unchecked")
+    // @Override
     public Entry<K, Object> next() {
       Entry<K, ?> entry = iterator.next();
       if (entry.getValue() instanceof LazyField) {
@@ -203,6 +146,7 @@ class LazyField {
       return (Entry<K, Object>) entry;
     }
 
+    // @Override
     public void remove() {
       iterator.remove();
     }

+ 202 - 13
java/src/main/java/com/google/protobuf/LazyStringArrayList.java

@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.AbstractList;
 import java.util.ArrayList;
@@ -39,9 +40,9 @@ import java.util.RandomAccess;
 
 /**
  * An implementation of {@link LazyStringList} that wraps an ArrayList. Each
- * element is either a ByteString or a String. It caches the last one requested
- * which is most likely the one needed next. This minimizes memory usage while
- * satisfying the most common use cases.
+ * element is one of String, ByteString, or byte[]. It caches the last one
+ * requested which is most likely the one needed next. This minimizes memory
+ * usage while satisfying the most common use cases.
  * <p>
  * <strong>Note that this implementation is not synchronized.</strong>
  * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
@@ -64,8 +65,8 @@ import java.util.RandomAccess;
 public class LazyStringArrayList extends AbstractList<String>
     implements LazyStringList, RandomAccess {
 
-  public final static LazyStringList EMPTY = new UnmodifiableLazyStringList(
-      new LazyStringArrayList());
+  public static final LazyStringList EMPTY =
+      new LazyStringArrayList().getUnmodifiableView();
 
   private final List<Object> list;
 
@@ -87,13 +88,20 @@ public class LazyStringArrayList extends AbstractList<String>
     Object o = list.get(index);
     if (o instanceof String) {
       return (String) o;
-    } else {
+    } else if (o instanceof ByteString) {
       ByteString bs = (ByteString) o;
       String s = bs.toStringUtf8();
       if (bs.isValidUtf8()) {
         list.set(index, s);
       }
       return s;
+    } else {
+      byte[] ba = (byte[]) o;
+      String s = Internal.toStringUtf8(ba);
+      if (Internal.isValidUtf8(ba)) {
+        list.set(index, s);
+      }
+      return s;
     }
   }
 
@@ -134,6 +142,20 @@ public class LazyStringArrayList extends AbstractList<String>
     return ret;
   }
 
+  // @Override
+  public boolean addAllByteString(Collection<? extends ByteString> values) {
+    boolean ret = list.addAll(values);
+    modCount++;
+    return ret;
+  }
+
+  // @Override
+  public boolean addAllByteArray(Collection<byte[]> c) {
+    boolean ret = list.addAll(c);
+    modCount++;
+    return ret;
+  }
+
   @Override
   public String remove(int index) {
     Object o = list.remove(index);
@@ -141,6 +163,7 @@ public class LazyStringArrayList extends AbstractList<String>
     return asString(o);
   }
 
+  @Override
   public void clear() {
     list.clear();
     modCount++;
@@ -151,28 +174,194 @@ public class LazyStringArrayList extends AbstractList<String>
     list.add(element);
     modCount++;
   }
+  
+  // @Override
+  public void add(byte[] element) {
+    list.add(element);
+    modCount++;
+  }
 
   // @Override
   public ByteString getByteString(int index) {
     Object o = list.get(index);
-    if (o instanceof String) {
-      ByteString b = ByteString.copyFromUtf8((String) o);
+    ByteString b = asByteString(o);
+    if (b != o) {
+      list.set(index, b);
+    }
+    return b;
+  }
+  
+  // @Override
+  public byte[] getByteArray(int index) {
+    Object o = list.get(index);
+    byte[] b = asByteArray(o);
+    if (b != o) {
       list.set(index, b);
-      return b;
-    } else {
-      return (ByteString) o;
     }
+    return b;
+  }
+
+  // @Override
+  public void set(int index, ByteString s) {
+    list.set(index, s);
+  }
+
+  // @Override
+  public void set(int index, byte[] s) {
+    list.set(index, s);
   }
 
-  private String asString(Object o) {
+
+  private static String asString(Object o) {
     if (o instanceof String) {
       return (String) o;
-    } else {
+    } else if (o instanceof ByteString) {
       return ((ByteString) o).toStringUtf8();
+    } else {
+      return Internal.toStringUtf8((byte[]) o);
+    }
+  }
+  
+  private static ByteString asByteString(Object o) {
+    if (o instanceof ByteString) {
+      return (ByteString) o;
+    } else if (o instanceof String) {
+      return ByteString.copyFromUtf8((String) o);
+    } else {
+      return ByteString.copyFrom((byte[]) o);
+    }
+  }
+  
+  private static byte[] asByteArray(Object o) {
+    if (o instanceof byte[]) {
+      return (byte[]) o;
+    } else if (o instanceof String) {
+      return Internal.toByteArray((String) o);
+    } else {
+      return ((ByteString) o).toByteArray();
     }
   }
 
+  // @Override
   public List<?> getUnderlyingElements() {
     return Collections.unmodifiableList(list);
   }
+
+  // @Override
+  public void mergeFrom(LazyStringList other) {
+    for (Object o : other.getUnderlyingElements()) {
+      if (o instanceof byte[]) {
+        byte[] b = (byte[]) o;
+        // Byte array's content is mutable so they should be copied rather than
+        // shared when merging from one message to another.
+        list.add(Arrays.copyOf(b, b.length));
+      } else {
+        list.add(o);
+      }
+    }
+  }
+
+  private static class ByteArrayListView extends AbstractList<byte[]>
+      implements RandomAccess {
+    private final List<Object> list;
+    
+    ByteArrayListView(List<Object> list) {
+      this.list = list;
+    }
+    
+    @Override
+    public byte[] get(int index) {
+      Object o = list.get(index);
+      byte[] b = asByteArray(o);
+      if (b != o) {
+        list.set(index, b);
+      }
+      return b;
+    }
+
+    @Override
+    public int size() {
+      return list.size();
+    }
+
+    @Override
+    public byte[] set(int index, byte[] s) {
+      Object o = list.set(index, s);
+      modCount++;
+      return asByteArray(o);
+    }
+
+    @Override
+    public void add(int index, byte[] s) {
+      list.add(index, s);
+      modCount++;
+    }
+
+    @Override
+    public byte[] remove(int index) {
+      Object o = list.remove(index);
+      modCount++;
+      return asByteArray(o);
+    }
+  }
+  
+  // @Override
+  public List<byte[]> asByteArrayList() {
+    return new ByteArrayListView(list);
+  }
+
+  private static class ByteStringListView extends AbstractList<ByteString>
+      implements RandomAccess {
+    private final List<Object> list;
+
+    ByteStringListView(List<Object> list) {
+      this.list = list;
+    }
+
+    @Override
+    public ByteString get(int index) {
+      Object o = list.get(index);
+      ByteString b = asByteString(o);
+      if (b != o) {
+        list.set(index, b);
+      }
+      return b;
+    }
+
+    @Override
+    public int size() {
+      return list.size();
+    }
+
+    @Override
+    public ByteString set(int index, ByteString s) {
+      Object o = list.set(index, s);
+      modCount++;
+      return asByteString(o);
+    }
+
+    @Override
+    public void add(int index, ByteString s) {
+      list.add(index, s);
+      modCount++;
+    }
+
+    @Override
+    public ByteString remove(int index) {
+      Object o = list.remove(index);
+      modCount++;
+      return asByteString(o);
+    }
+  }
+
+  // @Override
+  public List<ByteString> asByteStringList() {
+    return new ByteStringListView(list);
+  }
+
+  // @Override
+  public LazyStringList getUnmodifiableView() {
+    return new UnmodifiableLazyStringList(this);
+  }
+
 }

+ 96 - 14
java/src/main/java/com/google/protobuf/LazyStringList.java

@@ -30,25 +30,22 @@
 
 package com.google.protobuf;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
  * An interface extending {@code List<String>} that also provides access to the
- * items of the list as UTF8-encoded ByteString objects. This is used by the
- * protocol buffer implementation to support lazily converting bytes parsed
- * over the wire to String objects until needed and also increases the
+ * items of the list as UTF8-encoded ByteString or byte[] objects. This is
+ * used by the protocol buffer implementation to support lazily converting bytes
+ * parsed over the wire to String objects until needed and also increases the
  * efficiency of serialization if the String was never requested as the
- * ByteString is already cached.
- * <p>
- * This only adds additional methods that are required for the use in the
- * protocol buffer code in order to be able successfully round trip byte arrays
- * through parsing and serialization without conversion to strings. It's not
- * attempting to support the functionality of say {@code List<ByteString>}, hence
- * why only these two very specific methods are added.
+ * ByteString or byte[] is already cached. The ByteString methods are used in
+ * immutable API only and byte[] methods used in mutable API only for they use
+ * different representations for string/bytes fields.
  *
  * @author jonp@google.com (Jon Perlow)
  */
-public interface LazyStringList extends List<String> {
+public interface LazyStringList extends ProtocolStringList {
 
   /**
    * Returns the element at the specified position in this list as a ByteString.
@@ -59,6 +56,16 @@ public interface LazyStringList extends List<String> {
    *         ({@code index < 0 || index >= size()})
    */
   ByteString getByteString(int index);
+  
+  /**
+   * Returns the element at the specified position in this list as byte[].
+   *
+   * @param index index of the element to return
+   * @return the element at the specified position in this list
+   * @throws IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  byte[] getByteArray(int index);
 
   /**
    * Appends the specified element to the end of this list (optional
@@ -71,11 +78,86 @@ public interface LazyStringList extends List<String> {
   void add(ByteString element);
 
   /**
-   * Returns an unmodifiable List of the underlying elements, each of
-   * which is either a {@code String} or its equivalent UTF-8 encoded
-   * {@code ByteString}. It is an error for the caller to modify the returned
+   * Appends the specified element to the end of this list (optional
+   * operation).
+   *
+   * @param element element to be appended to this list
+   * @throws UnsupportedOperationException if the <tt>add</tt> operation
+   *         is not supported by this list
+   */
+  void add(byte[] element);
+
+  /**
+   * Replaces the element at the specified position in this list with the
+   * specified element (optional operation).
+   *
+   * @param index index of the element to replace
+   * @param element the element to be stored at the specified position
+   * @throws UnsupportedOperationException if the <tt>set</tt> operation
+   *         is not supported by this list
+   *         IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  void set(int index, ByteString element);
+  
+  /**
+   * Replaces the element at the specified position in this list with the
+   * specified element (optional operation).
+   *
+   * @param index index of the element to replace
+   * @param element the element to be stored at the specified position
+   * @throws UnsupportedOperationException if the <tt>set</tt> operation
+   *         is not supported by this list
+   *         IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  void set(int index, byte[] element);
+
+  /**
+   * Appends all elements in the specified ByteString collection to the end of
+   * this list.
+   *
+   * @param c collection whose elements are to be added to this list
+   * @return true if this list changed as a result of the call
+   * @throws UnsupportedOperationException if the <tt>addAllByteString</tt>
+   *         operation is not supported by this list
+   */
+  boolean addAllByteString(Collection<? extends ByteString> c);
+
+  /**
+   * Appends all elements in the specified byte[] collection to the end of
+   * this list.
+   *
+   * @param c collection whose elements are to be added to this list
+   * @return true if this list changed as a result of the call
+   * @throws UnsupportedOperationException if the <tt>addAllByteArray</tt>
+   *         operation is not supported by this list
+   */
+  boolean addAllByteArray(Collection<byte[]> c);
+
+  /**
+   * Returns an unmodifiable List of the underlying elements, each of which is
+   * either a {@code String} or its equivalent UTF-8 encoded {@code ByteString}
+   * or byte[]. It is an error for the caller to modify the returned
    * List, and attempting to do so will result in an
    * {@link UnsupportedOperationException}.
    */
   List<?> getUnderlyingElements();
+
+  /**
+   * Merges all elements from another LazyStringList into this one. This method
+   * differs from {@link #addAll(Collection)} on that underlying byte arrays are
+   * copied instead of reference shared. Immutable API doesn't need to use this
+   * method as byte[] is not used there at all.
+   */
+  void mergeFrom(LazyStringList other);
+
+  /**
+   * Returns a mutable view of this list. Changes to the view will be made into
+   * the original list. This method is used in mutable API only.
+   */
+  List<byte[]> asByteArrayList();
+
+  /** Returns an unmodifiable view of the list. */
+  LazyStringList getUnmodifiableView();
 }

+ 19 - 6
java/src/main/java/com/google/protobuf/LiteralByteString.java

@@ -142,6 +142,13 @@ class LiteralByteString extends ByteString {
     outputStream.write(toByteArray());
   }
 
+  @Override
+  void writeToInternal(OutputStream outputStream, int sourceOffset,
+      int numberToWrite) throws IOException {
+    outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset,
+        numberToWrite);
+  }
+
   @Override
   public String toString(String charsetName)
       throws UnsupportedEncodingException {
@@ -261,13 +268,20 @@ class LiteralByteString extends ByteString {
 
   @Override
   protected int partialHash(int h, int offset, int length) {
-    byte[] thisBytes = bytes;
-    for (int i = getOffsetIntoBytes() + offset, limit = i + length; i < limit;
-        i++) {
-      h = h * 31 + thisBytes[i];
+    return hashCode(h, bytes, getOffsetIntoBytes() + offset, length);
+  }
+  
+  static int hashCode(int h, byte[] bytes, int offset, int length) {
+    for (int i = offset; i < offset + length; i++) {
+      h = h * 31 + bytes[i];
     }
     return h;
   }
+  
+  static int hashCode(byte[] bytes) {
+    int h = hashCode(bytes.length, bytes, 0, bytes.length);
+    return h == 0 ? 1 : h;
+  }
 
   // =================================================================
   // Input stream
@@ -282,8 +296,7 @@ class LiteralByteString extends ByteString {
   public CodedInputStream newCodedInput() {
     // We trust CodedInputStream not to modify the bytes, or to give anyone
     // else access to them.
-    return CodedInputStream
-        .newInstance(bytes, getOffsetIntoBytes(), size());  // No copy
+    return CodedInputStream.newInstance(this);
   }
 
   // =================================================================

+ 7 - 0
java/src/main/java/com/google/protobuf/Message.java

@@ -53,6 +53,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
   // (From MessageLite, re-declared here only for return type covariance.)
   Parser<? extends Message> getParserForType();
 
+
   // -----------------------------------------------------------------
   // Comparison and hashing
 
@@ -179,6 +180,12 @@ public interface Message extends MessageLite, MessageOrBuilder {
      */
     Builder clearField(Descriptors.FieldDescriptor field);
 
+    /**
+     * Clears the oneof.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the oneof.
+     */
+    Builder clearOneof(Descriptors.OneofDescriptor oneof);
+
     /**
      * Sets an element of a repeated field to the given value.  The value must
      * be of the correct type for this field, i.e. the same type that

+ 1 - 0
java/src/main/java/com/google/protobuf/MessageLite.java

@@ -128,6 +128,7 @@ public interface MessageLite extends MessageLiteOrBuilder {
    */
   void writeDelimitedTo(OutputStream output) throws IOException;
 
+
   // =================================================================
   // Builders
 

+ 15 - 1
java/src/main/java/com/google/protobuf/MessageOrBuilder.java

@@ -76,7 +76,7 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
    * Returns a collection of all the fields in this message which are set
    * and their corresponding values.  A singular ("required" or "optional")
    * field is set iff hasField() returns true for that field.  A "repeated"
-   * field is set iff getRepeatedFieldSize() is greater than zero.  The
+   * field is set iff getRepeatedFieldCount() is greater than zero.  The
    * values are exactly what would be returned by calling
    * {@link #getField(Descriptors.FieldDescriptor)} for each field.  The map
    * is guaranteed to be a sorted map, so iterating over it will return fields
@@ -88,6 +88,20 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
    */
   Map<Descriptors.FieldDescriptor, Object> getAllFields();
 
+  /**
+   * Returns true if the given oneof is set.
+   * @throws IllegalArgumentException if
+   *           {@code oneof.getContainingType() != getDescriptorForType()}.
+   */
+  boolean hasOneof(Descriptors.OneofDescriptor oneof);
+
+  /**
+   * Obtains the FieldDescriptor if the given oneof is set. Returns null
+   * if no field is set.
+   */
+  Descriptors.FieldDescriptor getOneofFieldDescriptor(
+      Descriptors.OneofDescriptor oneof);
+
   /**
    * Returns true if the given field is set.  This is exactly equivalent to
    * calling the generated "has" accessor method corresponding to the field.

+ 931 - 0
java/src/main/java/com/google/protobuf/MessageReflection.java

@@ -0,0 +1,931 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Reflection utility methods shared by both mutable and immutable messages.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+class MessageReflection {
+
+  static void writeMessageTo(Message message, CodedOutputStream output,
+      boolean alwaysWriteRequiredFields)
+      throws IOException {
+    final boolean isMessageSet =
+        message.getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+    Map<FieldDescriptor, Object> fields = message.getAllFields();
+    if (alwaysWriteRequiredFields) {
+      fields = new TreeMap<FieldDescriptor, Object>(fields);
+      for (final FieldDescriptor field :
+          message.getDescriptorForType().getFields()) {
+        if (field.isRequired() && !fields.containsKey(field)) {
+          fields.put(field, message.getField(field));
+        }
+      }
+    }
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        fields.entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+      if (isMessageSet && field.isExtension() &&
+          field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+          !field.isRepeated()) {
+        output.writeMessageSetExtension(field.getNumber(), (Message) value);
+      } else {
+        FieldSet.writeField(field, value, output);
+      }
+    }
+
+    final UnknownFieldSet unknownFields = message.getUnknownFields();
+    if (isMessageSet) {
+      unknownFields.writeAsMessageSetTo(output);
+    } else {
+      unknownFields.writeTo(output);
+    }
+  }
+
+  static int getSerializedSize(Message message) {
+    int size = 0;
+    final boolean isMessageSet =
+        message.getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        message.getAllFields().entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+      if (isMessageSet && field.isExtension() &&
+          field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+          !field.isRepeated()) {
+        size += CodedOutputStream.computeMessageSetExtensionSize(
+            field.getNumber(), (Message) value);
+      } else {
+        size += FieldSet.computeFieldSize(field, value);
+      }
+    }
+
+    final UnknownFieldSet unknownFields = message.getUnknownFields();
+    if (isMessageSet) {
+      size += unknownFields.getSerializedSizeAsMessageSet();
+    } else {
+      size += unknownFields.getSerializedSize();
+    }
+    return size;
+  }
+
+  static String delimitWithCommas(List<String> parts) {
+    StringBuilder result = new StringBuilder();
+    for (String part : parts) {
+      if (result.length() > 0) {
+        result.append(", ");
+      }
+      result.append(part);
+    }
+    return result.toString();
+  }
+
+  @SuppressWarnings("unchecked")
+  static boolean isInitialized(MessageOrBuilder message) {
+    // Check that all required fields are present.
+    for (final Descriptors.FieldDescriptor field : message
+        .getDescriptorForType()
+        .getFields()) {
+      if (field.isRequired()) {
+        if (!message.hasField(field)) {
+          return false;
+        }
+      }
+    }
+
+    // Check that embedded messages are initialized.
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        message.getAllFields().entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          for (final Message element
+              : (List<Message>) entry.getValue()) {
+            if (!element.isInitialized()) {
+              return false;
+            }
+          }
+        } else {
+          if (!((Message) entry.getValue()).isInitialized()) {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  private static String subMessagePrefix(final String prefix,
+      final Descriptors.FieldDescriptor field,
+      final int index) {
+    final StringBuilder result = new StringBuilder(prefix);
+    if (field.isExtension()) {
+      result.append('(')
+          .append(field.getFullName())
+          .append(')');
+    } else {
+      result.append(field.getName());
+    }
+    if (index != -1) {
+      result.append('[')
+          .append(index)
+          .append(']');
+    }
+    result.append('.');
+    return result.toString();
+  }
+
+  private static void findMissingFields(final MessageOrBuilder message,
+      final String prefix,
+      final List<String> results) {
+    for (final Descriptors.FieldDescriptor field :
+        message.getDescriptorForType().getFields()) {
+      if (field.isRequired() && !message.hasField(field)) {
+        results.add(prefix + field.getName());
+      }
+    }
+
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        message.getAllFields().entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+
+      if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          int i = 0;
+          for (final Object element : (List) value) {
+            findMissingFields((MessageOrBuilder) element,
+                subMessagePrefix(prefix, field, i++),
+                results);
+          }
+        } else {
+          if (message.hasField(field)) {
+            findMissingFields((MessageOrBuilder) value,
+                subMessagePrefix(prefix, field, -1),
+                results);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Populates {@code this.missingFields} with the full "path" of each missing
+   * required field in the given message.
+   */
+  static List<String> findMissingFields(
+      final MessageOrBuilder message) {
+    final List<String> results = new ArrayList<String>();
+    findMissingFields(message, "", results);
+    return results;
+  }
+
+  static interface MergeTarget {
+    enum ContainerType {
+      MESSAGE, EXTENSION_SET
+    }
+
+    /**
+     * Returns the descriptor for the target.
+     */
+    public Descriptors.Descriptor getDescriptorForType();
+
+    public ContainerType getContainerType();
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByName(
+        ExtensionRegistry registry, String name);
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+        ExtensionRegistry registry, Descriptors.Descriptor containingType,
+        int fieldNumber);
+
+    /**
+     * Obtains the value of the given field, or the default value if it is not
+     * set.  For primitive fields, the boxed primitive value is returned. For
+     * enum fields, the EnumValueDescriptor for the value is returned. For
+     * embedded message fields, the sub-message is returned.  For repeated
+     * fields, a java.util.List is returned.
+     */
+    public Object getField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Returns true if the given field is set.  This is exactly equivalent to
+     * calling the generated "has" accessor method corresponding to the field.
+     *
+     * @throws IllegalArgumentException The field is a repeated field, or {@code
+     *     field.getContainingType() != getDescriptorForType()}.
+     */
+    boolean hasField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Sets a field to the given value.  The value must be of the correct type
+     * for this field, i.e. the same type that
+     * {@link Message#getField(Descriptors.FieldDescriptor)}
+     * would return.
+     */
+    MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
+
+    /**
+     * Clears the field.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the field.
+     */
+    MergeTarget clearField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Sets an element of a repeated field to the given value.  The value must
+     * be of the correct type for this field, i.e. the same type that {@link
+     * Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
+     *
+     * @throws IllegalArgumentException The field is not a repeated field, or
+     *                                  {@code field.getContainingType() !=
+     *                                  getDescriptorForType()}.
+     */
+    MergeTarget setRepeatedField(Descriptors.FieldDescriptor field,
+        int index, Object value);
+
+    /**
+     * Like {@code setRepeatedField}, but appends the value as a new element.
+     *
+     * @throws IllegalArgumentException The field is not a repeated field, or
+     *                                  {@code field.getContainingType() !=
+     *                                  getDescriptorForType()}.
+     */
+    MergeTarget addRepeatedField(Descriptors.FieldDescriptor field,
+        Object value);
+
+    /**
+     * Returns true if the given oneof is set.
+     *
+     * @throws IllegalArgumentException if
+     *           {@code oneof.getContainingType() != getDescriptorForType()}.
+     */
+    boolean hasOneof(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Clears the oneof.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the oneof.
+     */
+    MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Obtains the FieldDescriptor if the given oneof is set. Returns null
+     * if no field is set.
+     */
+    Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Parse the input stream into a sub field group defined based on either
+     * FieldDescriptor or the default instance.
+     */
+    Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+        throws IOException;
+
+    /**
+     * Parse the input stream into a sub field message defined based on either
+     * FieldDescriptor or the default instance.
+     */
+    Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+        throws IOException;
+
+    /**
+     * Parse from a ByteString into a sub field message defined based on either
+     * FieldDescriptor or the default instance.  There isn't a varint indicating
+     * the length of the message at the beginning of the input ByteString.
+     */
+    Object parseMessageFromBytes(
+        ByteString bytes, ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+        throws IOException;
+    
+    /**
+     * Read a primitive field from input. Note that builders and mutable
+     * messages may use different Java types to represent a primtive field.
+     */
+    Object readPrimitiveField(
+        CodedInputStream input, WireFormat.FieldType type,
+        boolean checkUtf8) throws IOException;
+
+    /**
+     * Returns a new merge target for a sub-field. When defaultInstance is
+     * provided, it indicates the descriptor is for an extension type, and
+     * implementations should create a new instance from the defaultInstance
+     * prototype directly.
+     */
+    MergeTarget newMergeTargetForField(
+        Descriptors.FieldDescriptor descriptor,
+        Message defaultInstance);
+
+    /**
+     * Finishes the merge and returns the underlying object.
+     */
+    Object finish();
+  }
+
+  static class BuilderAdapter implements MergeTarget {
+
+    private final Message.Builder builder;
+
+    public Descriptors.Descriptor getDescriptorForType() {
+      return builder.getDescriptorForType();
+    }
+
+    public BuilderAdapter(Message.Builder builder) {
+      this.builder = builder;
+    }
+
+    public Object getField(Descriptors.FieldDescriptor field) {
+      return builder.getField(field);
+    }
+
+    @Override
+    public boolean hasField(Descriptors.FieldDescriptor field) {
+      return builder.hasField(field);
+    }
+
+    public MergeTarget setField(Descriptors.FieldDescriptor field,
+        Object value) {
+      builder.setField(field, value);
+      return this;
+    }
+
+    public MergeTarget clearField(Descriptors.FieldDescriptor field) {
+      builder.clearField(field);
+      return this;
+    }
+
+    public MergeTarget setRepeatedField(
+        Descriptors.FieldDescriptor field, int index, Object value) {
+      builder.setRepeatedField(field, index, value);
+      return this;
+    }
+
+    public MergeTarget addRepeatedField(
+        Descriptors.FieldDescriptor field, Object value) {
+      builder.addRepeatedField(field, value);
+      return this;
+    }
+
+    @Override
+    public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
+      return builder.hasOneof(oneof);
+    }
+
+    @Override
+    public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
+      builder.clearOneof(oneof);
+      return this;
+    }
+
+    @Override
+    public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
+      return builder.getOneofFieldDescriptor(oneof);
+    }
+
+    public ContainerType getContainerType() {
+      return ContainerType.MESSAGE;
+    }
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByName(
+        ExtensionRegistry registry, String name) {
+      return registry.findImmutableExtensionByName(name);
+    }
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+        ExtensionRegistry registry, Descriptors.Descriptor containingType,
+        int fieldNumber) {
+      return registry.findImmutableExtensionByNumber(containingType,
+          fieldNumber);
+    }
+
+    public Object parseGroup(CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        Descriptors.FieldDescriptor field, Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder;
+      // When default instance is not null. The field is an extension field.
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+      return subBuilder.buildPartial();
+    }
+
+    public Object parseMessage(CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        Descriptors.FieldDescriptor field, Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder;
+      // When default instance is not null. The field is an extension field.
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readMessage(subBuilder, extensionRegistry);
+      return subBuilder.buildPartial();
+    }
+
+    public Object parseMessageFromBytes(ByteString bytes,
+        ExtensionRegistryLite extensionRegistry,
+        Descriptors.FieldDescriptor field, Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder;
+      // When default instance is not null. The field is an extension field.
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      subBuilder.mergeFrom(bytes, extensionRegistry);
+      return subBuilder.buildPartial();
+    }
+
+    public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field,
+        Message defaultInstance) {
+      if (defaultInstance != null) {
+        return new BuilderAdapter(
+            defaultInstance.newBuilderForType());
+      } else {
+        return new BuilderAdapter(builder.newBuilderForField(field));
+      }
+    }
+    
+    public Object readPrimitiveField(
+        CodedInputStream input, WireFormat.FieldType type,
+        boolean checkUtf8) throws IOException {
+      return FieldSet.readPrimitiveField(input, type, checkUtf8);
+    }
+
+    public Object finish() {
+      return builder.buildPartial();
+    }
+  }
+
+
+  static class ExtensionAdapter implements MergeTarget {
+
+    private final FieldSet<Descriptors.FieldDescriptor> extensions;
+
+    ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
+    public Descriptors.Descriptor getDescriptorForType() {
+      throw new UnsupportedOperationException(
+          "getDescriptorForType() called on FieldSet object");
+    }
+
+    public Object getField(Descriptors.FieldDescriptor field) {
+      return extensions.getField(field);
+    }
+
+    public boolean hasField(Descriptors.FieldDescriptor field) {
+      return extensions.hasField(field);
+    }
+
+    public MergeTarget setField(Descriptors.FieldDescriptor field,
+        Object value) {
+      extensions.setField(field, value);
+      return this;
+    }
+
+    public MergeTarget clearField(Descriptors.FieldDescriptor field) {
+      extensions.clearField(field);
+      return this;
+    }
+
+    public MergeTarget setRepeatedField(
+        Descriptors.FieldDescriptor field, int index, Object value) {
+      extensions.setRepeatedField(field, index, value);
+      return this;
+    }
+
+    public MergeTarget addRepeatedField(
+        Descriptors.FieldDescriptor field, Object value) {
+      extensions.addRepeatedField(field, value);
+      return this;
+    }
+
+    @Override
+    public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
+      return false;
+    }
+
+    @Override
+    public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
+      // Nothing to clear.
+      return this;
+    }
+
+    @Override
+    public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
+      return null;
+    }
+
+    public ContainerType getContainerType() {
+      return ContainerType.EXTENSION_SET;
+    }
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByName(
+        ExtensionRegistry registry, String name) {
+      return registry.findImmutableExtensionByName(name);
+    }
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+        ExtensionRegistry registry, Descriptors.Descriptor containingType,
+        int fieldNumber) {
+      return registry.findImmutableExtensionByNumber(containingType,
+          fieldNumber);
+    }
+
+    public Object parseGroup(CodedInputStream input,
+        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
+        Message defaultInstance) throws IOException {
+      Message.Builder subBuilder =
+          defaultInstance.newBuilderForType();
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readGroup(field.getNumber(), subBuilder, registry);
+      return subBuilder.buildPartial();
+    }
+
+    public Object parseMessage(CodedInputStream input,
+        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
+        Message defaultInstance) throws IOException {
+      Message.Builder subBuilder =
+          defaultInstance.newBuilderForType();
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readMessage(subBuilder, registry);
+      return subBuilder.buildPartial();
+    }
+
+    public Object parseMessageFromBytes(ByteString bytes,
+        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
+        Message defaultInstance) throws IOException {
+      Message.Builder subBuilder =  defaultInstance.newBuilderForType();
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      subBuilder.mergeFrom(bytes, registry);
+      return subBuilder.buildPartial();
+    }
+
+    public MergeTarget newMergeTargetForField(
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
+      throw new UnsupportedOperationException(
+          "newMergeTargetForField() called on FieldSet object");
+    }
+    
+    public Object readPrimitiveField(
+        CodedInputStream input, WireFormat.FieldType type,
+        boolean checkUtf8) throws IOException {
+      return FieldSet.readPrimitiveField(input, type, checkUtf8);
+    }
+
+    public Object finish() {
+      throw new UnsupportedOperationException(
+          "finish() called on FieldSet object");
+    }
+  }
+
+  /**
+   * Parses a single field into MergeTarget. The target can be Message.Builder,
+   * FieldSet or MutableMessage.
+   *
+   * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+   *
+   * @param tag The tag, which should have already been read.
+   * @return {@code true} unless the tag is an end-group tag.
+   */
+  static boolean mergeFieldFrom(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      Descriptors.Descriptor type,
+      MergeTarget target,
+      int tag) throws IOException {
+    if (type.getOptions().getMessageSetWireFormat() &&
+        tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+      mergeMessageSetExtensionFromCodedStream(
+          input, unknownFields, extensionRegistry, type, target);
+      return true;
+    }
+
+    final int wireType = WireFormat.getTagWireType(tag);
+    final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+    final Descriptors.FieldDescriptor field;
+    Message defaultInstance = null;
+
+    if (type.isExtensionNumber(fieldNumber)) {
+      // extensionRegistry may be either ExtensionRegistry or
+      // ExtensionRegistryLite.  Since the type we are parsing is a full
+      // message, only a full ExtensionRegistry could possibly contain
+      // extensions of it.  Otherwise we will treat the registry as if it
+      // were empty.
+      if (extensionRegistry instanceof ExtensionRegistry) {
+        final ExtensionRegistry.ExtensionInfo extension =
+            target.findExtensionByNumber((ExtensionRegistry) extensionRegistry,
+                type, fieldNumber);
+        if (extension == null) {
+          field = null;
+        } else {
+          field = extension.descriptor;
+          defaultInstance = extension.defaultInstance;
+          if (defaultInstance == null &&
+              field.getJavaType()
+                  == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+            throw new IllegalStateException(
+                "Message-typed extension lacked default instance: " +
+                    field.getFullName());
+          }
+        }
+      } else {
+        field = null;
+      }
+    } else if (target.getContainerType() == MergeTarget.ContainerType.MESSAGE) {
+      field = type.findFieldByNumber(fieldNumber);
+    } else {
+      field = null;
+    }
+
+    boolean unknown = false;
+    boolean packed = false;
+    if (field == null) {
+      unknown = true;  // Unknown field.
+    } else if (wireType == FieldSet.getWireFormatForFieldType(
+        field.getLiteType(),
+        false  /* isPacked */)) {
+      packed = false;
+    } else if (field.isPackable() &&
+        wireType == FieldSet.getWireFormatForFieldType(
+            field.getLiteType(),
+            true  /* isPacked */)) {
+      packed = true;
+    } else {
+      unknown = true;  // Unknown wire type.
+    }
+
+    if (unknown) {  // Unknown field or wrong wire type.  Skip.
+      return unknownFields.mergeFieldFrom(tag, input);
+    }
+
+    if (packed) {
+      final int length = input.readRawVarint32();
+      final int limit = input.pushLimit(length);
+      if (field.getLiteType() == WireFormat.FieldType.ENUM) {
+        while (input.getBytesUntilLimit() > 0) {
+          final int rawValue = input.readEnum();
+          final Object value = field.getEnumType().findValueByNumber(rawValue);
+          if (value == null) {
+            // If the number isn't recognized as a valid value for this
+            // enum, drop it (don't even add it to unknownFields).
+            return true;
+          }
+          target.addRepeatedField(field, value);
+        }
+      } else {
+        while (input.getBytesUntilLimit() > 0) {
+          final Object value =
+              target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
+          target.addRepeatedField(field, value);
+        }
+      }
+      input.popLimit(limit);
+    } else {
+      final Object value;
+      switch (field.getType()) {
+        case GROUP: {
+          value = target
+              .parseGroup(input, extensionRegistry, field, defaultInstance);
+          break;
+        }
+        case MESSAGE: {
+          value = target
+              .parseMessage(input, extensionRegistry, field, defaultInstance);
+          break;
+        }
+        case ENUM:
+          final int rawValue = input.readEnum();
+          value = field.getEnumType().findValueByNumber(rawValue);
+          // If the number isn't recognized as a valid value for this enum,
+          // drop it.
+          if (value == null) {
+            unknownFields.mergeVarintField(fieldNumber, rawValue);
+            return true;
+          }
+          break;
+        default:
+          value = target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
+          break;
+      }
+
+      if (field.isRepeated()) {
+        target.addRepeatedField(field, value);
+      } else {
+        target.setField(field, value);
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
+   * MergeTarget.
+   */
+  private static void mergeMessageSetExtensionFromCodedStream(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      Descriptors.Descriptor type,
+      MergeTarget target) throws IOException {
+
+    // The wire format for MessageSet is:
+    //   message MessageSet {
+    //     repeated group Item = 1 {
+    //       required int32 typeId = 2;
+    //       required bytes message = 3;
+    //     }
+    //   }
+    // "typeId" is the extension's field number.  The extension can only be
+    // a message type, where "message" contains the encoded bytes of that
+    // message.
+    //
+    // In practice, we will probably never see a MessageSet item in which
+    // the message appears before the type ID, or where either field does not
+    // appear exactly once.  However, in theory such cases are valid, so we
+    // should be prepared to accept them.
+
+    int typeId = 0;
+    ByteString rawBytes = null; // If we encounter "message" before "typeId"
+    ExtensionRegistry.ExtensionInfo extension = null;
+
+    // Read bytes from input, if we get it's type first then parse it eagerly,
+    // otherwise we store the raw bytes in a local variable.
+    while (true) {
+      final int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+
+      if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+        typeId = input.readUInt32();
+        if (typeId != 0) {
+          // extensionRegistry may be either ExtensionRegistry or
+          // ExtensionRegistryLite. Since the type we are parsing is a full
+          // message, only a full ExtensionRegistry could possibly contain
+          // extensions of it. Otherwise we will treat the registry as if it
+          // were empty.
+          if (extensionRegistry instanceof ExtensionRegistry) {
+            extension = target.findExtensionByNumber(
+                (ExtensionRegistry) extensionRegistry, type, typeId);
+          }
+        }
+
+      } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+        if (typeId != 0) {
+          if (extension != null &&
+              ExtensionRegistryLite.isEagerlyParseMessageSets()) {
+            // We already know the type, so we can parse directly from the
+            // input with no copying.  Hooray!
+            eagerlyMergeMessageSetExtension(
+                input, extension, extensionRegistry, target);
+            rawBytes = null;
+            continue;
+          }
+        }
+        // We haven't seen a type ID yet or we want parse message lazily.
+        rawBytes = input.readBytes();
+
+      } else { // Unknown tag. Skip it.
+        if (!input.skipField(tag)) {
+          break; // End of group
+        }
+      }
+    }
+    input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+    // Process the raw bytes.
+    if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
+      if (extension != null) { // We known the type
+        mergeMessageSetExtensionFromBytes(
+            rawBytes, extension, extensionRegistry, target);
+      } else { // We don't know how to parse this. Ignore it.
+        if (rawBytes != null) {
+          unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
+              .addLengthDelimited(rawBytes).build());
+        }
+      }
+    }
+  }
+
+  private static void mergeMessageSetExtensionFromBytes(
+      ByteString rawBytes,
+      ExtensionRegistry.ExtensionInfo extension,
+      ExtensionRegistryLite extensionRegistry,
+      MergeTarget target) throws IOException {
+
+    Descriptors.FieldDescriptor field = extension.descriptor;
+    boolean hasOriginalValue = target.hasField(field);
+
+    if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
+      // If the field already exists, we just parse the field.
+      Object value = target.parseMessageFromBytes(
+          rawBytes, extensionRegistry,field, extension.defaultInstance);
+      target.setField(field, value);
+    } else {
+      // Use LazyField to load MessageSet lazily.
+      LazyField lazyField = new LazyField(
+          extension.defaultInstance, extensionRegistry, rawBytes);
+      target.setField(field, lazyField);
+    }
+  }
+
+  private static void eagerlyMergeMessageSetExtension(
+      CodedInputStream input,
+      ExtensionRegistry.ExtensionInfo extension,
+      ExtensionRegistryLite extensionRegistry,
+      MergeTarget target) throws IOException {
+    Descriptors.FieldDescriptor field = extension.descriptor;
+    Object value = target.parseMessage(input, extensionRegistry, field,
+                                       extension.defaultInstance);
+    target.setField(field, value);
+  }
+}

+ 2 - 0
java/src/main/java/com/google/protobuf/Parser.java

@@ -35,6 +35,8 @@ import java.io.InputStream;
 /**
  * Abstract interface for parsing Protocol Messages.
  *
+ * The implementation should be stateless and thread-safe.
+ *
  * @author liujisi@google.com (Pherl Liu)
  */
 public interface Parser<MessageType> {

+ 48 - 0
java/src/main/java/com/google/protobuf/ProtocolStringList.java

@@ -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.
+
+package com.google.protobuf;
+
+import java.util.List;
+
+/**
+ * An interface extending {@code List<String>} used for repeated string fields
+ * to provide optional access to the data as a list of ByteStrings. The
+ * underlying implementation stores values as either ByteStrings or Strings
+ * (see {@link LazyStringArrayList}) depending on how the value was initialized
+ * or last read, and it is often more efficient to deal with lists of
+ * ByteStrings when handling protos that have been deserialized from bytes.
+ */
+public interface ProtocolStringList extends List<String> {
+
+  /** Returns a view of the data as a list of ByteStrings. */
+  List<ByteString> asByteStringList();
+
+}

+ 14 - 0
java/src/main/java/com/google/protobuf/RopeByteString.java

@@ -401,6 +401,20 @@ class RopeByteString extends ByteString {
     right.writeTo(outputStream);
   }
 
+  @Override
+  void writeToInternal(OutputStream out, int sourceOffset,
+      int numberToWrite) throws IOException {
+    if (sourceOffset + numberToWrite <= leftLength) {
+      left.writeToInternal(out, sourceOffset, numberToWrite);
+    } else if (sourceOffset >= leftLength) {
+      right.writeToInternal(out, sourceOffset - leftLength, numberToWrite);
+    } else {
+      int numberToWriteInLeft = leftLength - sourceOffset;
+      left.writeToInternal(out, sourceOffset, numberToWriteInLeft);
+      right.writeToInternal(out, 0, numberToWrite - numberToWriteInLeft);
+    }
+  }
+
   @Override
   public String toString(String charsetName)
       throws UnsupportedEncodingException {

+ 2 - 3
java/src/main/java/com/google/protobuf/RpcUtil.java

@@ -91,9 +91,8 @@ public final class RpcUtil {
   @SuppressWarnings("unchecked")
   private static <Type extends Message> Type copyAsType(
       final Type typeDefaultInstance, final Message source) {
-    return (Type)typeDefaultInstance.newBuilderForType()
-                                    .mergeFrom(source)
-                                    .build();
+    return (Type) typeDefaultInstance
+        .newBuilderForType().mergeFrom(source).build();
   }
 
   /**

File diff suppressed because it is too large
+ 599 - 186
java/src/main/java/com/google/protobuf/TextFormat.java


+ 17 - 0
java/src/main/java/com/google/protobuf/UnknownFieldSet.java

@@ -91,6 +91,7 @@ public final class UnknownFieldSet implements MessageLite {
   }
   private Map<Integer, Field> fields;
 
+
   @Override
   public boolean equals(final Object other) {
     if (this == other) {
@@ -367,6 +368,22 @@ public final class UnknownFieldSet implements MessageLite {
       reinitialize();
       return this;
     }
+    
+    /** Clear fields from the set with a given field number. */
+    public Builder clearField(final int number) {
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      if (lastField != null && lastFieldNumber == number) {
+        // Discard this.
+        lastField = null;
+        lastFieldNumber = 0;
+      }
+      if (fields.containsKey(number)) {
+        fields.remove(number);
+      }
+      return this;
+    }
 
     /**
      * Merge the fields from {@code other} into this set.  If a field number

+ 55 - 2
java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java

@@ -31,10 +31,12 @@
 package com.google.protobuf;
 
 import java.util.AbstractList;
-import java.util.RandomAccess;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
-import java.util.Iterator;
+import java.util.RandomAccess;
 
 /**
  * An implementation of {@link LazyStringList} that wraps another
@@ -72,6 +74,36 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
   }
 
   //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public void set(int index, ByteString element) {
+    throw new UnsupportedOperationException();
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public boolean addAllByteString(Collection<? extends ByteString> element) {
+    throw new UnsupportedOperationException();
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public byte[] getByteArray(int index) {
+    return list.getByteArray(index);
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public void add(byte[] element) {
+    throw new UnsupportedOperationException();
+  }
+  
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public void set(int index, byte[] element) {
+    throw new UnsupportedOperationException();
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public boolean addAllByteArray(Collection<byte[]> element) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
   public ListIterator<String> listIterator(final int index) {
     return new ListIterator<String>() {
       ListIterator<String> iter = list.listIterator(index);
@@ -145,8 +177,29 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
     };
   }
 
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
   public List<?> getUnderlyingElements() {
     // The returned value is already unmodifiable.
     return list.getUnderlyingElements();
   }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public void mergeFrom(LazyStringList other) {
+    throw new UnsupportedOperationException();
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public List<byte[]> asByteArrayList() {
+    return Collections.unmodifiableList(list.asByteArrayList());
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public List<ByteString> asByteStringList() {
+    return Collections.unmodifiableList(list.asByteStringList());
+  }
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public LazyStringList getUnmodifiableView() {
+    return this;
+  }
 }

+ 18 - 0
java/src/test/java/com/google/protobuf/AbstractMessageTest.java

@@ -506,4 +506,22 @@ public class AbstractMessageTest extends TestCase {
         String.format("%s should have a different hash code from %s", m1, m2),
         m1.hashCode() == m2.hashCode());
   }
+
+  public void testCheckByteStringIsUtf8OnUtf8() {
+    ByteString byteString = ByteString.copyFromUtf8("some text");
+    AbstractMessageLite.checkByteStringIsUtf8(byteString);
+    // No exception thrown.
+  }
+
+  public void testCheckByteStringIsUtf8OnNonUtf8() {
+    ByteString byteString =
+        ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
+    try {
+      AbstractMessageLite.checkByteStringIsUtf8(byteString);
+      fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
 }

+ 67 - 0
java/src/test/java/com/google/protobuf/ByteStringTest.java

@@ -35,6 +35,7 @@ import com.google.protobuf.ByteString.Output;
 import junit.framework.TestCase;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -676,6 +677,21 @@ public class ByteStringTest extends TestCase {
     assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
   }
 
+  public void testEndsWith() {
+    byte[] bytes = getTestBytes(1000, 1234L);
+    ByteString string = ByteString.copyFrom(bytes);
+    ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
+    ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
+    assertTrue(string.endsWith(ByteString.EMPTY));
+    assertTrue(string.endsWith(string));
+    assertTrue(string.endsWith(suffix));
+    assertFalse(string.endsWith(prefix));
+    assertFalse(suffix.endsWith(prefix));
+    assertFalse(prefix.endsWith(suffix));
+    assertFalse(ByteString.EMPTY.endsWith(suffix));
+    assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY));
+  }
+
   static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
     List<ByteString> pieces = new ArrayList<ByteString>();
     // Starting length should be small enough that we'll do some concatenating by
@@ -689,4 +705,55 @@ public class ByteStringTest extends TestCase {
     }
     return pieces;
   }
+  
+  private byte[] substringUsingWriteTo(
+      ByteString data, int offset, int length) throws IOException {
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    data.writeTo(output, offset, length);
+    return output.toByteArray();
+  }
+  
+  public void testWriteToOutputStream() throws Exception {
+    // Choose a size large enough so when two ByteStrings are concatenated they
+    // won't be merged into one byte array due to some optimizations.
+    final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1;
+    byte[] data1 = new byte[dataSize];
+    for (int i = 0; i < data1.length; i++) {
+      data1[i] = (byte) 1;
+    }
+    data1[1] = (byte) 11;
+    // Test LiteralByteString.writeTo(OutputStream,int,int)
+    LiteralByteString left = new LiteralByteString(data1);
+    byte[] result = substringUsingWriteTo(left, 1, 1);
+    assertEquals(1, result.length);
+    assertEquals((byte) 11, result[0]);
+    
+    byte[] data2 = new byte[dataSize];
+    for (int i = 0; i < data1.length; i++) {
+      data2[i] = (byte) 2;
+    }
+    LiteralByteString right = new LiteralByteString(data2);
+    // Concatenate two ByteStrings to create a RopeByteString.
+    ByteString root = left.concat(right);
+    // Make sure we are actually testing a RopeByteString with a simple tree
+    // structure.
+    assertEquals(1, root.getTreeDepth());
+    // Write parts of the left node.
+    result = substringUsingWriteTo(root, 0, dataSize);
+    assertEquals(dataSize, result.length);
+    assertEquals((byte) 1, result[0]);
+    assertEquals((byte) 1, result[dataSize - 1]);
+    // Write parts of the right node.
+    result = substringUsingWriteTo(root, dataSize, dataSize);
+    assertEquals(dataSize, result.length);
+    assertEquals((byte) 2, result[0]);
+    assertEquals((byte) 2, result[dataSize - 1]);
+    // Write a segment of bytes that runs across both nodes.
+    result = substringUsingWriteTo(root, dataSize / 2, dataSize);
+    assertEquals(dataSize, result.length);
+    assertEquals((byte) 1, result[0]);
+    assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]);
+    assertEquals((byte) 2, result[dataSize - dataSize / 2]);
+    assertEquals((byte) 2, result[dataSize - 1]);
+  }
 }

+ 141 - 0
java/src/test/java/com/google/protobuf/CheckUtf8Test.java

@@ -0,0 +1,141 @@
+// 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.
+
+package com.google.protobuf;
+
+import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
+import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
+import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
+import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
+import junit.framework.TestCase;
+
+/**
+ * Test that protos generated with file option java_string_check_utf8 do in
+ * fact perform appropriate UTF-8 checks.
+ *
+ * @author jbaum@google.com (Jacob Butcher)
+ */
+public class CheckUtf8Test extends TestCase {
+
+  private static final String UTF8_BYTE_STRING_TEXT = "some text";
+  private static final ByteString UTF8_BYTE_STRING =
+      ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
+  private static final ByteString NON_UTF8_BYTE_STRING =
+      ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
+
+  public void testBuildRequiredStringWithGoodUtf8() throws Exception {
+    assertEquals(UTF8_BYTE_STRING_TEXT,
+                 StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
+  }
+
+  public void testParseRequiredStringWithGoodUtf8() throws Exception {
+    ByteString serialized =
+        BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString();
+    assertEquals(UTF8_BYTE_STRING_TEXT,
+                 StringWrapper.PARSER.parseFrom(serialized).getReq());
+  }
+
+  public void testBuildRequiredStringWithBadUtf8() throws Exception {
+    try {
+      StringWrapper.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildOptionalStringWithBadUtf8() throws Exception {
+    try {
+      StringWrapper.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildRepeatedStringWithBadUtf8() throws Exception {
+    try {
+      StringWrapper.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testParseRequiredStringWithBadUtf8() throws Exception {
+    ByteString serialized =
+        BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+    try {
+      StringWrapper.PARSER.parseFrom(serialized);
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
+    try {
+      StringWrapperSize.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildOptionalStringWithBadUtf8Size() throws Exception {
+    try {
+      StringWrapperSize.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildRepeatedStringWithBadUtf8Size() throws Exception {
+    try {
+      StringWrapperSize.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testParseRequiredStringWithBadUtf8Size() throws Exception {
+    ByteString serialized =
+        BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+    try {
+      StringWrapperSize.PARSER.parseFrom(serialized);
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+  }
+
+}

+ 260 - 19
java/src/test/java/com/google/protobuf/CodedInputStreamTest.java

@@ -30,15 +30,20 @@
 
 package com.google.protobuf;
 
+import protobuf_unittest.UnittestProto.BoolMessage;
+import protobuf_unittest.UnittestProto.Int32Message;
+import protobuf_unittest.UnittestProto.Int64Message;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
 
 import junit.framework.TestCase;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.FilterInputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
 
 /**
  * Unit test for {@link CodedInputStream}.
@@ -85,28 +90,54 @@ public class CodedInputStreamTest extends TestCase {
     }
   }
 
+  private void assertDataConsumed(byte[] data, CodedInputStream input)
+      throws IOException {
+    assertEquals(data.length, input.getTotalBytesRead());
+    assertTrue(input.isAtEnd());
+  }
+
   /**
    * Parses the given bytes using readRawVarint32() and readRawVarint64() and
    * checks that the result matches the given value.
    */
   private void assertReadVarint(byte[] data, long value) throws Exception {
     CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals((int)value, input.readRawVarint32());
+    assertEquals((int) value, input.readRawVarint32());
+    assertDataConsumed(data, input);
 
     input = CodedInputStream.newInstance(data);
     assertEquals(value, input.readRawVarint64());
-    assertTrue(input.isAtEnd());
+    assertDataConsumed(data, input);
+
+    input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawVarint64SlowPath());
+    assertDataConsumed(data, input);
+
+    input = CodedInputStream.newInstance(data);
+    assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
+    assertDataConsumed(data, input);
 
     // Try different block sizes.
     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
       input = CodedInputStream.newInstance(
         new SmallBlockInputStream(data, blockSize));
-      assertEquals((int)value, input.readRawVarint32());
+      assertEquals((int) value, input.readRawVarint32());
+      assertDataConsumed(data, input);
 
       input = CodedInputStream.newInstance(
         new SmallBlockInputStream(data, blockSize));
       assertEquals(value, input.readRawVarint64());
-      assertTrue(input.isAtEnd());
+      assertDataConsumed(data, input);
+
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawVarint64SlowPath());
+      assertDataConsumed(data, input);
+
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
+      assertDataConsumed(data, input);
     }
 
     // Try reading direct from an InputStream.  We want to verify that it
@@ -115,7 +146,7 @@ public class CodedInputStreamTest extends TestCase {
     byte[] longerData = new byte[data.length + 1];
     System.arraycopy(data, 0, longerData, 0, data.length);
     InputStream rawInput = new ByteArrayInputStream(longerData);
-    assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput));
+    assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
     assertEquals(1, rawInput.available());
   }
 
@@ -143,6 +174,14 @@ public class CodedInputStreamTest extends TestCase {
       assertEquals(expected.getMessage(), e.getMessage());
     }
 
+    input = CodedInputStream.newInstance(data);
+    try {
+      input.readRawVarint64SlowPath();
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+
     // Make sure we get the same error when reading direct from an InputStream.
     try {
       CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
@@ -311,6 +350,7 @@ public class CodedInputStreamTest extends TestCase {
     }
   }
 
+
   /**
    * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
    * exactly up to a limit, this should not break things.
@@ -350,7 +390,7 @@ public class CodedInputStreamTest extends TestCase {
     // Allocate and initialize a 1MB blob.
     byte[] blob = new byte[1 << 20];
     for (int i = 0; i < blob.length; i++) {
-      blob[i] = (byte)i;
+      blob[i] = (byte) i;
     }
 
     // Make a message containing it.
@@ -437,16 +477,23 @@ public class CodedInputStreamTest extends TestCase {
     }
   }
 
+  private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
+      assertEquals(
+          InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
+          e.getMessage());
+  }
+
   public void testSizeLimit() throws Exception {
     CodedInputStream input = CodedInputStream.newInstance(
-      TestUtil.getAllSet().toByteString().newInput());
+        new SmallBlockInputStream(
+            TestUtil.getAllSet().toByteString().newInput(), 16));
     input.setSizeLimit(16);
 
     try {
       TestAllTypes.parseFrom(input);
       fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
+    } catch (InvalidProtocolBufferException expected) {
+      checkSizeLimitExceeded(expected);
     }
   }
 
@@ -460,8 +507,8 @@ public class CodedInputStreamTest extends TestCase {
     try {
       input.readRawByte();
       fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
+    } catch (InvalidProtocolBufferException expected) {
+      checkSizeLimitExceeded(expected);
     }
 
     input.resetSizeCounter();
@@ -469,28 +516,50 @@ public class CodedInputStreamTest extends TestCase {
     input.readRawByte();  // No exception thrown.
     input.resetSizeCounter();
     assertEquals(0, input.getTotalBytesRead());
+    input.readRawBytes(16);
+    assertEquals(16, input.getTotalBytesRead());
+    input.resetSizeCounter();
 
     try {
-      input.readRawBytes(16);  // Hits limit again.
+      input.readRawBytes(17);  // Hits limit again.
       fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
+    } catch (InvalidProtocolBufferException expected) {
+      checkSizeLimitExceeded(expected);
+    }
+  }
+
+  public void testSizeLimitMultipleMessages() throws Exception {
+    byte[] bytes = new byte[256];
+    for (int i = 0; i < bytes.length; i++) {
+      bytes[i] = (byte) i;
+    }
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(bytes, 7));
+    input.setSizeLimit(16);
+    for (int i = 0; i < 256 / 16; i++) {
+      byte[] message = input.readRawBytes(16);
+      for (int j = 0; j < message.length; j++) {
+        assertEquals(i * 16 + j, message[j] & 0xff);
+      }
+      assertEquals(16, input.getTotalBytesRead());
+      input.resetSizeCounter();
+      assertEquals(0, input.getTotalBytesRead());
     }
   }
 
   /**
-   * Tests that if we read an string that contains invalid UTF-8, no exception
+   * Tests that if we readString invalid UTF-8 bytes, no exception
    * is thrown.  Instead, the invalid bytes are replaced with the Unicode
    * "replacement character" U+FFFD.
    */
-  public void testReadInvalidUtf8() throws Exception {
+  public void testReadStringInvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte)0x80 });
+    output.writeRawBytes(new byte[] { (byte) 0x80 });
     output.flush();
 
     CodedInputStream input = rawOutput.toByteString().newCodedInput();
@@ -499,13 +568,37 @@ public class CodedInputStreamTest extends TestCase {
     assertEquals(0xfffd, text.charAt(0));
   }
 
+  /**
+   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
+   * InvalidProtocolBufferException is thrown.
+   */
+  public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.flush();
+
+    CodedInputStream input = rawOutput.toByteString().newCodedInput();
+    assertEquals(tag, input.readTag());
+    try {
+      input.readStringRequireUtf8();
+      fail("Expected invalid UTF-8 exception.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+  }
+
   public void testReadFromSlice() throws Exception {
     byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
     CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
     assertEquals(0, in.getTotalBytesRead());
     for (int i = 3; i < 8; i++) {
       assertEquals(i, in.readRawByte());
-      assertEquals(i-2, in.getTotalBytesRead());
+      assertEquals(i - 2, in.getTotalBytesRead());
     }
     // eof
     assertEquals(0, in.readTag());
@@ -525,4 +618,152 @@ public class CodedInputStreamTest extends TestCase {
       }
     }
   }
+
+  public void testReadByteArray() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    // Zero-sized bytes field.
+    output.writeRawVarint32(0);
+    // One one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 23 });
+    // Another one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 45 });
+    // A bytes field large enough that won't fit into the 4K buffer.
+    final int bytesLength = 16 * 1024;
+    byte[] bytes = new byte[bytesLength];
+    bytes[0] = (byte) 67;
+    bytes[bytesLength - 1] = (byte) 89;
+    output.writeRawVarint32(bytesLength);
+    output.writeRawBytes(bytes);
+
+    output.flush();
+    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
+
+    byte[] result = inputStream.readByteArray();
+    assertEquals(0, result.length);
+    result = inputStream.readByteArray();
+    assertEquals(1, result.length);
+    assertEquals((byte) 23, result[0]);
+    result = inputStream.readByteArray();
+    assertEquals(1, result.length);
+    assertEquals((byte) 45, result[0]);
+    result = inputStream.readByteArray();
+    assertEquals(bytesLength, result.length);
+    assertEquals((byte) 67, result[0]);
+    assertEquals((byte) 89, result[bytesLength - 1]);
+  }
+
+  public void testReadByteBuffer() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    // Zero-sized bytes field.
+    output.writeRawVarint32(0);
+    // One one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 23});
+    // Another one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 45});
+    // A bytes field large enough that won't fit into the 4K buffer.
+    final int bytesLength = 16 * 1024;
+    byte[] bytes = new byte[bytesLength];
+    bytes[0] = (byte) 67;
+    bytes[bytesLength - 1] = (byte) 89;
+    output.writeRawVarint32(bytesLength);
+    output.writeRawBytes(bytes);
+
+    output.flush();
+    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
+
+    ByteBuffer result = inputStream.readByteBuffer();
+    assertEquals(0, result.capacity());
+    result = inputStream.readByteBuffer();
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 23, result.get());
+    result = inputStream.readByteBuffer();
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 45, result.get());
+    result = inputStream.readByteBuffer();
+    assertEquals(bytesLength, result.capacity());
+    assertEquals((byte) 67, result.get());
+    result.position(bytesLength - 1);
+    assertEquals((byte) 89, result.get());
+  }
+
+  public void testReadByteBufferAliasing() throws Exception {
+    ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
+    // Zero-sized bytes field.
+    output.writeRawVarint32(0);
+    // One one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 23});
+    // Another one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 45});
+    // A bytes field large enough that won't fit into the 4K buffer.
+    final int bytesLength = 16 * 1024;
+    byte[] bytes = new byte[bytesLength];
+    bytes[0] = (byte) 67;
+    bytes[bytesLength - 1] = (byte) 89;
+    output.writeRawVarint32(bytesLength);
+    output.writeRawBytes(bytes);
+    output.flush();
+    byte[] data = byteArrayStream.toByteArray();
+
+    // Without aliasing
+    CodedInputStream inputStream = CodedInputStream.newInstance(data);
+    ByteBuffer result = inputStream.readByteBuffer();
+    assertEquals(0, result.capacity());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() != data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 23, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() != data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 45, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() != data);
+    assertEquals(bytesLength, result.capacity());
+    assertEquals((byte) 67, result.get());
+    result.position(bytesLength - 1);
+    assertEquals((byte) 89, result.get());
+
+    // Enable aliasing
+    inputStream = CodedInputStream.newInstance(data);
+    inputStream.enableAliasing(true);
+    result = inputStream.readByteBuffer();
+    assertEquals(0, result.capacity());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() == data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 23, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() == data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 45, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() == data);
+    assertEquals(bytesLength, result.capacity());
+    assertEquals((byte) 67, result.get());
+    result.position(bytesLength - 1);
+    assertEquals((byte) 89, result.get());
+  }
+
+  public void testCompatibleTypes() throws Exception {
+    long data = 0x100000000L;
+    Int64Message message = Int64Message.newBuilder().setData(data).build();
+    ByteString serialized = message.toByteString();
+
+    // Test int64(long) is compatible with bool(boolean)
+    BoolMessage msg2 = BoolMessage.parseFrom(serialized);
+    assertTrue(msg2.getData());
+
+    // Test int64(long) is compatible with int32(int)
+    Int32Message msg3 = Int32Message.parseFrom(serialized);
+    assertEquals((int) data, msg3.getData());
+  }
 }

+ 84 - 0
java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java

@@ -38,6 +38,7 @@ import protobuf_unittest.UnittestProto.TestSparseEnum;
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -314,4 +315,87 @@ public class CodedOutputStreamTest extends TestCase {
     SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
     assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
   }
+
+  /** Test getTotalBytesWritten() */
+  public void testGetTotalBytesWritten() throws Exception {
+    final int BUFFER_SIZE = 4 * 1024;
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE);
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+    byte[] value = "abcde".getBytes("UTF-8");
+    for (int i = 0; i < 1024; ++i) {
+      codedStream.writeRawBytes(value, 0, value.length);
+    }
+    // Make sure we have written more bytes than the buffer could hold. This is
+    // to make the test complete.
+    assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
+    assertEquals(value.length * 1024, codedStream.getTotalBytesWritten());
+  }
+  
+  public void testWriteToByteBuffer() throws Exception {
+    final int bufferSize = 16 * 1024;
+    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(buffer);
+    // Write raw bytes into the ByteBuffer.
+    final int length1 = 5000;
+    for (int i = 0; i < length1; i++) {
+      codedStream.writeRawByte((byte) 1);
+    }
+    final int length2 = 8 * 1024;
+    byte[] data = new byte[length2];
+    for (int i = 0; i < length2; i++) {
+      data[i] = (byte) 2;
+    }
+    codedStream.writeRawBytes(data);
+    final int length3 = bufferSize - length1 - length2;
+    for (int i = 0; i < length3; i++) {
+      codedStream.writeRawByte((byte) 3);
+    }
+    codedStream.flush();
+    
+    // Check that data is correctly written to the ByteBuffer.
+    assertEquals(0, buffer.remaining());
+    buffer.flip();
+    for (int i = 0; i < length1; i++) {
+      assertEquals((byte) 1, buffer.get());
+    }
+    for (int i = 0; i < length2; i++) {
+      assertEquals((byte) 2, buffer.get());
+    }
+    for (int i = 0; i < length3; i++) {
+      assertEquals((byte) 3, buffer.get());
+    }
+  }
+  
+  public void testWriteByteBuffer() throws Exception {
+    byte[] value = "abcde".getBytes("UTF-8");
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+    ByteBuffer byteBuffer = ByteBuffer.wrap(value, 0, 1);
+    // This will actually write 5 bytes into the CodedOutputStream as the
+    // ByteBuffer's capacity() is 5.
+    codedStream.writeRawBytes(byteBuffer);
+    // The above call shouldn't affect the ByteBuffer's state.
+    assertEquals(0, byteBuffer.position());
+    assertEquals(1, byteBuffer.limit());
+    
+    // The correct way to write part of an array using ByteBuffer.
+    codedStream.writeRawBytes(ByteBuffer.wrap(value, 2, 1).slice());
+    
+    codedStream.flush();
+    byte[] result = outputStream.toByteArray();
+    assertEquals(6, result.length);
+    for (int i = 0; i < 5; i++) {
+      assertEquals(value[i], result[i]);
+    }
+    assertEquals(value[2], result[5]);
+  }
+
+  public void testWriteByteArrayWithOffsets() throws Exception {
+    byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
+    byte[] destination = new byte[4];
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
+    codedStream.writeByteArrayNoTag(fullArray, 2, 2);
+    assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
+    assertEquals(3, codedStream.getTotalBytesWritten());
+  }
 }

+ 63 - 3
java/src/test/java/com/google/protobuf/DescriptorsTest.java

@@ -39,6 +39,7 @@ import com.google.protobuf.Descriptors.DescriptorValidationException;
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.ServiceDescriptor;
@@ -53,10 +54,13 @@ import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
 import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestService;
 import protobuf_unittest.UnittestCustomOptions;
 
+import protobuf_unittest.TestCustomOptions;
+
 
 import junit.framework.TestCase;
 
@@ -308,6 +312,7 @@ public class DescriptorsTest extends TestCase {
     EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
     assertEquals(value, enumType.getValues().get(0));
     assertEquals("FOREIGN_FOO", value.getName());
+    assertEquals("FOREIGN_FOO", value.toString());
     assertEquals(4, value.getNumber());
     assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
     assertEquals(value, enumType.findValueByNumber(4));
@@ -324,7 +329,6 @@ public class DescriptorsTest extends TestCase {
     assertEquals("protobuf_unittest.TestService", service.getFullName());
     assertEquals(UnittestProto.getDescriptor(), service.getFile());
 
-    assertEquals(2, service.getMethods().size());
 
     MethodDescriptor fooMethod = service.getMethods().get(0);
     assertEquals("Foo", fooMethod.getName());
@@ -351,8 +355,12 @@ public class DescriptorsTest extends TestCase {
 
 
   public void testCustomOptions() throws Exception {
+    // Get the descriptor indirectly from a dependent proto class. This is to
+    // ensure that when a proto class is loaded, custom options defined in its
+    // dependencies are also properly initialized.
     Descriptor descriptor =
-      UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor();
+        TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
+        .findFieldByName("field").getMessageType();
 
     assertTrue(
       descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
@@ -511,9 +519,35 @@ public class DescriptorsTest extends TestCase {
     assertTrue(barFound);
   }
   
+  public void testDependencyOrder() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto").build();
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .addDependency("foo.proto")
+        .build();
+    FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
+        .setName("baz.proto")
+        .addDependency("foo.proto")
+        .addDependency("bar.proto")
+        .addPublicDependency(0)
+        .addPublicDependency(1)
+        .build();
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
+        new FileDescriptor[0]);
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
+        new FileDescriptor[] {fooFile});
+    
+    // Items in the FileDescriptor array can be in any order. 
+    Descriptors.FileDescriptor.buildFrom(bazProto,
+        new FileDescriptor[] {fooFile, barFile});
+    Descriptors.FileDescriptor.buildFrom(bazProto,
+        new FileDescriptor[] {barFile, fooFile});
+  }
+  
   public void testInvalidPublicDependency() throws Exception {
     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto") .build();
+        .setName("foo.proto").build();
     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
         .setName("boo.proto")
         .addDependency("foo.proto")
@@ -645,4 +679,30 @@ public class DescriptorsTest extends TestCase {
           "a.b.c.d.bar.shared"));
     }   
   }
+
+  public void testOneofDescriptor() throws Exception {
+    Descriptor messageType = TestAllTypes.getDescriptor();
+    FieldDescriptor field =
+        messageType.findFieldByName("oneof_nested_message");
+    OneofDescriptor oneofDescriptor = field.getContainingOneof();
+    assertNotNull(oneofDescriptor);
+    assertSame(oneofDescriptor, messageType.getOneofs().get(0));
+    assertEquals("oneof_field", oneofDescriptor.getName());
+
+    assertEquals(4, oneofDescriptor.getFieldCount());
+    assertSame(oneofDescriptor.getField(1), field);
+  }
+
+  public void testMessageDescriptorExtensions() throws Exception {
+    assertFalse(TestAllTypes.getDescriptor().isExtendable());
+    assertTrue(TestAllExtensions.getDescriptor().isExtendable());
+    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
+
+    assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
+    assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
+    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
+    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
+    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
+    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
+  }
 }

+ 46 - 0
java/src/test/java/com/google/protobuf/DynamicMessageTest.java

@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
@@ -241,6 +244,19 @@ public class DynamicMessageTest extends TestCase {
 
     DynamicMessage copy = DynamicMessage.newBuilder(message).build();
     reflectionTester.assertAllFieldsSetViaReflection(copy);
+
+    // Test oneof behavior
+    FieldDescriptor bytesField =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+    FieldDescriptor uint32Field =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
+    assertTrue(copy.hasField(bytesField));
+    assertFalse(copy.hasField(uint32Field));
+    DynamicMessage copy2 =
+        DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
+    assertFalse(copy2.hasField(bytesField));
+    assertTrue(copy2.hasField(uint32Field));
+    assertEquals(123, copy2.getField(uint32Field));
   }
 
   public void testToBuilder() throws Exception {
@@ -261,4 +277,34 @@ public class DynamicMessageTest extends TestCase {
     assertEquals(Arrays.asList(unknownFieldVal),
         derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
   }
+
+  public void testDynamicOneofMessage() throws Exception {
+    DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
+    assertFalse(builder.hasOneof(oneof));
+    assertSame(null, builder.getOneofFieldDescriptor(oneof));
+
+    reflectionTester.setAllFieldsViaReflection(builder);
+    assertTrue(builder.hasOneof(oneof));
+    FieldDescriptor field = oneof.getField(3);
+    assertSame(field, builder.getOneofFieldDescriptor(oneof));
+
+    DynamicMessage message = builder.buildPartial();
+    assertTrue(message.hasOneof(oneof));
+
+    DynamicMessage.Builder mergedBuilder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    FieldDescriptor mergedField = oneof.getField(0);
+    mergedBuilder.setField(mergedField, 123);
+    assertTrue(mergedBuilder.hasField(mergedField));
+    mergedBuilder.mergeFrom(message);
+    assertTrue(mergedBuilder.hasField(field));
+    assertFalse(mergedBuilder.hasField(mergedField));
+
+    builder.clearOneof(oneof);
+    assertSame(null, builder.getOneofFieldDescriptor(oneof));
+    message = builder.build();
+    assertSame(null, message.getOneofFieldDescriptor(oneof));
+  }
 }

+ 370 - 1
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -45,6 +45,9 @@ import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
 import protobuf_unittest.NonNestedExtensionLite;
 import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended;
 import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite;
+import protobuf_unittest.OuterClassNameTest2OuterClass;
+import protobuf_unittest.OuterClassNameTest3OuterClass;
+import protobuf_unittest.OuterClassNameTestOuterClass;
 import protobuf_unittest.ServiceWithNoOuter;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
@@ -58,6 +61,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
 
@@ -69,6 +73,7 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -399,6 +404,44 @@ public class GeneratedMessageTest extends TestCase {
       // We expect this exception.
     }
   }
+  
+  public void testRepeatedAppendIterateOnlyOnce() throws Exception {
+    // Create a Iterable that can only be iterated once.
+    Iterable<String> stringIterable = new Iterable<String>() {
+      private boolean called = false;
+      @Override
+      public Iterator<String> iterator() {
+        if (called) {
+          throw new IllegalStateException();
+        }
+        called = true;
+        return Arrays.asList("one", "two", "three").iterator();
+      }
+    };
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addAllRepeatedString(stringIterable);
+    assertEquals(3, builder.getRepeatedStringCount());
+    assertEquals("one", builder.getRepeatedString(0));
+    assertEquals("two", builder.getRepeatedString(1));
+    assertEquals("three", builder.getRepeatedString(2));
+
+    try {
+      builder.addAllRepeatedString(stringIterable);
+      fail("Exception was not thrown");
+    } catch (IllegalStateException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testMergeFromOtherRejectsNull() throws Exception {
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      builder.mergeFrom((TestAllTypes) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
 
   public void testSettingForeignMessageUsingBuilder() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder()
@@ -496,6 +539,34 @@ public class GeneratedMessageTest extends TestCase {
       TestAllTypes.newBuilder().build());
   }
 
+  public void testReflectionGetOneof() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Descriptors.OneofDescriptor oneof =
+        TestAllTypes.getDescriptor().getOneofs().get(0);
+    Descriptors.FieldDescriptor field =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+    assertSame(field, builder.getOneofFieldDescriptor(oneof));
+
+    TestAllTypes message = builder.build();
+    assertSame(field, message.getOneofFieldDescriptor(oneof));
+  }
+
+  public void testReflectionClearOneof() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Descriptors.OneofDescriptor oneof =
+        TestAllTypes.getDescriptor().getOneofs().get(0);
+    Descriptors.FieldDescriptor field =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+
+    assertTrue(builder.hasOneof(oneof));
+    assertTrue(builder.hasField(field));
+    builder.clearOneof(oneof);
+    assertFalse(builder.hasOneof(oneof));
+    assertFalse(builder.hasField(field));
+  }
+
   public void testEnumInterface() throws Exception {
     assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum()
         instanceof ProtocolMessageEnum);
@@ -697,6 +768,15 @@ public class GeneratedMessageTest extends TestCase {
   // =================================================================
   // multiple_files_test
 
+  // Test that custom options of an file level enum are properly initialized.
+  // This test needs to be put before any other access to MultipleFilesTestProto
+  // or messages defined in multiple_files_test.proto because the class loading
+  // order affects initialization process of custom options.
+  public void testEnumValueOptionsInMultipleFilesMode() throws Exception {
+    assertEquals(12345, EnumWithNoOuter.FOO.getValueDescriptor().getOptions()
+        .getExtension(MultipleFilesTestProto.enumValueOption).intValue());
+  }
+
   public void testMultipleFilesOption() throws Exception {
     // We mostly just want to check that things compile.
     MessageWithNoOuter message =
@@ -795,7 +875,7 @@ public class GeneratedMessageTest extends TestCase {
     UnittestProto.TestRecursiveMessage message =
         UnittestProto.TestRecursiveMessage.getDefaultInstance();
     assertTrue(message != null);
-    assertTrue(message.getA() != null);
+    assertNotNull(message.getA());
     assertTrue(message.getA() == message);
   }
 
@@ -1143,4 +1223,293 @@ public class GeneratedMessageTest extends TestCase {
       // We expect this exception.
     }
   }
+
+  // Test that when the default outer class name conflicts with another type
+  // defined in the proto the compiler will append a suffix to avoid the
+  // conflict.
+  public void testConflictingOuterClassName() {
+    // We just need to make sure we can refer to the outer class with the
+    // expected name. There is nothing else to test.
+    OuterClassNameTestOuterClass.OuterClassNameTest message =
+        OuterClassNameTestOuterClass.OuterClassNameTest.newBuilder().build();
+    assertTrue(message.getDescriptorForType() ==
+        OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor());
+
+    OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2
+        message2 = OuterClassNameTest2OuterClass.TestMessage2.NestedMessage
+            .OuterClassNameTest2.newBuilder().build();
+    assertEquals(0, message2.getSerializedSize());
+
+    OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3
+        enumValue = OuterClassNameTest3OuterClass.TestMessage3.NestedMessage
+            .OuterClassNameTest3.DUMMY_VALUE;
+    assertEquals(1, enumValue.getNumber());
+  }
+
+  // =================================================================
+  // oneof generated code test
+  public void testOneofEnumCase() throws Exception {
+    TestOneof2 message = TestOneof2.newBuilder()
+        .setFooInt(123).setFooString("foo").setFooCord("bar").build();
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+  }
+
+  public void testClearOneof() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder().setFooInt(123);
+    assertEquals(TestOneof2.FooCase.FOO_INT, builder.getFooCase());
+    builder.clearFoo();
+    assertEquals(TestOneof2.FooCase.FOO_NOT_SET, builder.getFooCase());
+  }
+
+  public void testSetOneofClearsOthers() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestOneof2 message =
+        builder.setFooInt(123).setFooString("foo").buildPartial();
+    assertTrue(message.hasFooString());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooCord("bar").buildPartial();
+    assertTrue(message.hasFooCord());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooStringPiece("baz").buildPartial();
+    assertTrue(message.hasFooStringPiece());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooBytes(TestUtil.toBytes("qux")).buildPartial();
+    assertTrue(message.hasFooBytes());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooEnum(TestOneof2.NestedEnum.FOO).buildPartial();
+    assertTrue(message.hasFooEnum());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooMessage(
+        TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).buildPartial();
+    assertTrue(message.hasFooMessage());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooInt(123).buildPartial();
+    assertTrue(message.hasFooInt());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+  }
+
+  public void testOneofTypes() throws Exception {
+    // Primitive
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooInt(), 0);
+      assertFalse(builder.hasFooInt());
+      assertTrue(builder.setFooInt(123).hasFooInt());
+      assertEquals(builder.getFooInt(), 123);
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooInt());
+      assertEquals(message.getFooInt(), 123);
+
+      assertFalse(builder.clearFooInt().hasFooInt());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooInt());
+      assertEquals(message2.getFooInt(), 0);
+    }
+
+    // Enum
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO);
+      assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
+      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR);
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooEnum());
+      assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR);
+
+      assertFalse(builder.clearFooEnum().hasFooEnum());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooEnum());
+      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO);
+    }
+
+    // String
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooString(), "");
+      builder.setFooString("foo");
+      assertTrue(builder.hasFooString());
+      assertEquals(builder.getFooString(), "foo");
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooString());
+      assertEquals(message.getFooString(), "foo");
+      assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
+
+      assertFalse(builder.clearFooString().hasFooString());
+      TestOneof2 message2 = builder.buildPartial();
+      assertFalse(message2.hasFooString());
+      assertEquals(message2.getFooString(), "");
+      assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
+
+      // Get method should not change the oneof value.
+      builder.setFooInt(123);
+      assertEquals(builder.getFooString(), "");
+      assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
+      assertEquals(123, builder.getFooInt());
+
+      message = builder.build();
+      assertEquals(message.getFooString(), "");
+      assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
+      assertEquals(123, message.getFooInt());
+    }
+
+    // Cord
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooCord(), "");
+      builder.setFooCord("foo");
+      assertTrue(builder.hasFooCord());
+      assertEquals(builder.getFooCord(), "foo");
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooCord());
+      assertEquals(message.getFooCord(), "foo");
+      assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
+
+      assertFalse(builder.clearFooCord().hasFooCord());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooCord());
+      assertEquals(message2.getFooCord(), "");
+      assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
+    }
+
+    // StringPiece
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooStringPiece(), "");
+      builder.setFooStringPiece("foo");
+      assertTrue(builder.hasFooStringPiece());
+      assertEquals(builder.getFooStringPiece(), "foo");
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooStringPiece());
+      assertEquals(message.getFooStringPiece(), "foo");
+      assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
+
+      assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooStringPiece());
+      assertEquals(message2.getFooStringPiece(), "");
+      assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
+    }
+
+    // Message
+    {
+      // set
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooMessage().getQuxInt(), 0);
+      builder.setFooMessage(
+          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
+      assertTrue(builder.hasFooMessage());
+      assertEquals(builder.getFooMessage().getQuxInt(), 234);
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooMessage());
+      assertEquals(message.getFooMessage().getQuxInt(), 234);
+
+      // clear
+      assertFalse(builder.clearFooMessage().hasFooString());
+      message = builder.build();
+      assertFalse(message.hasFooMessage());
+      assertEquals(message.getFooMessage().getQuxInt(), 0);
+
+      // nested builder
+      builder = TestOneof2.newBuilder();
+      assertSame(builder.getFooMessageOrBuilder(),
+          TestOneof2.NestedMessage.getDefaultInstance());
+      assertFalse(builder.hasFooMessage());
+      builder.getFooMessageBuilder().setQuxInt(123);
+      assertTrue(builder.hasFooMessage());
+      assertEquals(builder.getFooMessage().getQuxInt(), 123);
+      message = builder.build();
+      assertTrue(message.hasFooMessage());
+      assertEquals(message.getFooMessage().getQuxInt(), 123);
+    }
+
+    // LazyMessage is tested in LazyMessageLiteTest.java
+  }
+
+  public void testOneofMerge() throws Exception {
+    // Primitive Type
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooInt(123).build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooInt());
+      assertEquals(message2.getFooInt(), 123);
+    }
+
+    // String
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooString("foo").build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooString());
+      assertEquals(message2.getFooString(), "foo");
+    }
+
+    // Enum
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooEnum());
+      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+    }
+
+    // Message
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooMessage(
+          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooMessage());
+      assertEquals(message2.getFooMessage().getQuxInt(), 234);
+    }
+  }
+
+  public void testOneofSerialization() throws Exception {
+    // Primitive Type
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooInt(123).build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooInt());
+      assertEquals(message2.getFooInt(), 123);
+    }
+
+    // String
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooString("foo").build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooString());
+      assertEquals(message2.getFooString(), "foo");
+    }
+
+    // Enum
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooEnum());
+      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+    }
+
+    // Message
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooMessage(
+          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooMessage());
+      assertEquals(message2.getFooMessage().getQuxInt(), 234);
+    }
+  }
 }

+ 134 - 0
java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java

@@ -0,0 +1,134 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import java.io.IOException;
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link LazyFieldLite}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldLiteTest extends TestCase {
+
+  public void testGetValue() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testGetValueEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+  }
+
+  public void testSetValue() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+    message = lazyField.getValue(TestAllTypes.getDefaultInstance());
+    changeValue(lazyField);
+    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testSetValueEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+    MessageLite value = lazyField.getValue(TestAllExtensions.getDefaultInstance());
+    changeValue(lazyField);
+    assertEquals(value, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+  }
+
+  public void testGetSerializedSize() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+    changeValue(lazyField);
+    assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
+  }
+
+  public void testGetSerializedSizeEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+    changeValue(lazyField);
+    assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
+  }
+
+  public void testGetByteString() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.toByteString(), lazyField.toByteString());
+    changeValue(lazyField);
+    assertNotEqual(message.toByteString(), lazyField.toByteString());
+  }
+
+  public void testGetByteStringEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.toByteString(), lazyField.toByteString());
+    changeValue(lazyField);
+    assertNotEqual(message.toByteString(), lazyField.toByteString());
+  }
+
+
+  // Help methods.
+
+  private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) {
+    ByteString bytes = message.toByteString();
+    return new LazyFieldLite(TestUtil.getExtensionRegistry(), bytes);
+  }
+
+  private void changeValue(LazyFieldLite lazyField) {
+    TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
+    builder.addRepeatedBool(true);
+    MessageLite newMessage = builder.build();
+    lazyField.setValue(newMessage);
+  }
+
+  private void assertNotEqual(Object unexpected, Object actual) {
+    assertFalse(unexpected == actual
+        || (unexpected != null && unexpected.equals(actual)));
+  }
+
+}

+ 121 - 0
java/src/test/java/com/google/protobuf/LazyFieldTest.java

@@ -0,0 +1,121 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import java.io.IOException;
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link LazyField}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldTest extends TestCase {
+  public void testHashCode() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyField lazyField =
+        createLazyFieldFromMessage(message);
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    lazyField.getValue();
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    changeValue(lazyField);
+    // make sure two messages have different hash code
+    assertNotEqual(message.hashCode(), lazyField.hashCode());
+  }
+
+  public void testHashCodeEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    lazyField.getValue();
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    changeValue(lazyField);
+    // make sure two messages have different hash code
+    assertNotEqual(message.hashCode(), lazyField.hashCode());
+  }
+
+  public void testGetValue() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertEquals(message, lazyField.getValue());
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue());
+  }
+
+  public void testGetValueEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertEquals(message, lazyField.getValue());
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue());
+  }
+
+  public void testEqualsObject() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertTrue(lazyField.equals(message));
+    changeValue(lazyField);
+    assertFalse(lazyField.equals(message));
+    assertFalse(message.equals(lazyField.getValue()));
+  }
+
+  public void testEqualsObjectEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertTrue(lazyField.equals(message));
+    changeValue(lazyField);
+    assertFalse(lazyField.equals(message));
+    assertFalse(message.equals(lazyField.getValue()));
+  }
+
+  // Help methods.
+
+  private LazyField createLazyFieldFromMessage(MessageLite message) {
+    ByteString bytes = message.toByteString();
+    return new LazyField(message.getDefaultInstanceForType(),
+        TestUtil.getExtensionRegistry(), bytes);
+  }
+
+  private void changeValue(LazyField lazyField) {
+    TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
+    builder.addRepeatedBool(true);
+    MessageLite newMessage = builder.build();
+    lazyField.setValue(newMessage);
+  }
+
+  private void assertNotEqual(Object unexpected, Object actual) {
+    assertFalse(unexpected == actual
+        || (unexpected != null && unexpected.equals(actual)));
+  }
+}

+ 319 - 0
java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java

@@ -0,0 +1,319 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
+import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
+import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
+
+import junit.framework.TestCase;
+
+import org.easymock.classextension.EasyMock;
+
+import java.util.ArrayList;
+
+/**
+ * Unit test for messages with lazy fields.
+ *
+ * @author niwasaki@google.com (Naoki Iwasaki)
+ */
+public class LazyMessageLiteTest extends TestCase {
+
+  private Parser<LazyInnerMessageLite> originalLazyInnerMessageLiteParser;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    originalLazyInnerMessageLiteParser = LazyInnerMessageLite.PARSER;
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    LazyInnerMessageLite.PARSER = originalLazyInnerMessageLiteParser;
+
+    super.tearDown();
+  }
+
+  public void testSetValues() {
+    LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
+        .setNum(3)
+        .build();
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(2)
+        .setNested(nested)
+        .build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .setInner(inner)
+        .setOneofNum(123)
+        .setOneofInner(inner)
+        .build();
+
+    assertEquals(1, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+
+    assertEquals(2, outer.getInner().getNum());
+    assertEquals(42, outer.getInner().getNumWithDefault());
+
+    assertEquals(3, outer.getInner().getNested().getNum());
+    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+
+    assertFalse(outer.hasOneofNum());
+    assertTrue(outer.hasOneofInner());
+
+    assertEquals(2, outer.getOneofInner().getNum());
+    assertEquals(42, outer.getOneofInner().getNumWithDefault());
+    assertEquals(3, outer.getOneofInner().getNested().getNum());
+    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+  }
+
+  public void testSetRepeatedValues() {
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+        .build();
+
+    assertEquals(1, outer.getNum());
+    assertEquals(2, outer.getRepeatedInnerCount());
+    assertEquals(119, outer.getRepeatedInner(0).getNum());
+    assertEquals(122, outer.getRepeatedInner(1).getNum());
+  }
+
+  public void testAddAll() {
+    ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();
+    int count = 4;
+    for (int i = 0; i < count; i++) {
+      LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+          .setNum(i)
+          .build();
+      inners.add(inner);
+    }
+
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .addAllRepeatedInner(inners)
+        .build();
+    assertEquals(count, outer.getRepeatedInnerCount());
+    for (int i = 0; i < count; i++) {
+      assertEquals(i, outer.getRepeatedInner(i).getNum());
+    }
+  }
+
+  public void testGetDefaultValues() {
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .build();
+
+    assertEquals(0, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+
+    assertEquals(0, outer.getInner().getNum());
+    assertEquals(42, outer.getInner().getNumWithDefault());
+
+    assertEquals(0, outer.getInner().getNested().getNum());
+    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+
+    assertEquals(0, outer.getOneofNum());
+
+    assertEquals(0, outer.getOneofInner().getNum());
+    assertEquals(42, outer.getOneofInner().getNumWithDefault());
+    assertEquals(0, outer.getOneofInner().getNested().getNum());
+    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+  }
+
+  public void testClearValues() {
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(115)
+        .build();
+
+    LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder();
+
+    assertEquals(0, outerBuilder.build().getNum());
+
+
+    // Set/Clear num
+    outerBuilder.setNum(100);
+
+    assertEquals(100, outerBuilder.build().getNum());
+    assertEquals(421, outerBuilder.build().getNumWithDefault());
+    assertFalse(outerBuilder.build().hasInner());
+
+    outerBuilder.clearNum();
+
+    assertEquals(0, outerBuilder.build().getNum());
+    assertEquals(421, outerBuilder.build().getNumWithDefault());
+    assertFalse(outerBuilder.build().hasInner());
+
+
+    // Set/Clear all
+    outerBuilder.setNum(100)
+        .setInner(inner)
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+        .setOneofInner(LazyInnerMessageLite.newBuilder().setNum(123));
+
+    LazyMessageLite outer = outerBuilder.build();
+    assertEquals(100, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+    assertTrue(outer.hasInner());
+    assertEquals(115, outer.getInner().getNum());
+    assertEquals(2, outer.getRepeatedInnerCount());
+    assertEquals(119, outer.getRepeatedInner(0).getNum());
+    assertEquals(122, outer.getRepeatedInner(1).getNum());
+    assertTrue(outer.hasOneofInner());
+    assertEquals(123, outer.getOneofInner().getNum());
+
+    outerBuilder.clear();
+
+    outer = outerBuilder.build();
+
+    assertEquals(0, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+    assertFalse(outer.hasInner());
+    assertEquals(0, outer.getRepeatedInnerCount());
+    assertFalse(outer.hasOneofInner());
+    assertEquals(0, outer.getOneofInner().getNum());
+  }
+
+  public void testMergeValues() {
+    LazyMessageLite outerBase = LazyMessageLite.newBuilder()
+        .setNumWithDefault(122)
+        .build();
+
+    LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder()
+        .setNum(115)
+        .build();
+    LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
+        .setNum(119)
+        .setInner(innerMerging)
+        .setOneofInner(innerMerging)
+        .build();
+
+    LazyMessageLite merged = LazyMessageLite
+        .newBuilder(outerBase)
+        .mergeFrom(outerMerging)
+        .build();
+    assertEquals(119, merged.getNum());
+    assertEquals(122, merged.getNumWithDefault());
+    assertEquals(115, merged.getInner().getNum());
+    assertEquals(42, merged.getInner().getNumWithDefault());
+    assertEquals(115, merged.getOneofInner().getNum());
+    assertEquals(42, merged.getOneofInner().getNumWithDefault());
+  }
+
+  public void testMergeDefaultValues() {
+    LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder()
+        .setNum(115)
+        .build();
+    LazyMessageLite outerBase = LazyMessageLite.newBuilder()
+        .setNum(119)
+        .setNumWithDefault(122)
+        .setInner(innerBase)
+        .setOneofInner(innerBase)
+        .build();
+
+    LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
+        .build();
+
+    LazyMessageLite merged = LazyMessageLite
+        .newBuilder(outerBase)
+        .mergeFrom(outerMerging)
+        .build();
+    // Merging default-instance shouldn't overwrite values in the base message.
+    assertEquals(119, merged.getNum());
+    assertEquals(122, merged.getNumWithDefault());
+    assertEquals(115, merged.getInner().getNum());
+    assertEquals(42, merged.getInner().getNumWithDefault());
+    assertEquals(115, merged.getOneofInner().getNum());
+    assertEquals(42, merged.getOneofInner().getNumWithDefault());
+  }
+
+  public void testSerialize() throws InvalidProtocolBufferException {
+    LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
+        .setNum(3)
+        .build();
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(2)
+        .setNested(nested)
+        .build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .setInner(inner)
+        .setOneofInner(inner)
+        .build();
+
+    ByteString bytes = outer.toByteString();
+    assertEquals(bytes.size(), outer.getSerializedSize());
+
+    LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
+
+    assertEquals(1, deserialized.getNum());
+    assertEquals(421,  deserialized.getNumWithDefault());
+
+    assertEquals(2,  deserialized.getInner().getNum());
+    assertEquals(42,  deserialized.getInner().getNumWithDefault());
+
+    assertEquals(3,  deserialized.getInner().getNested().getNum());
+    assertEquals(4,  deserialized.getInner().getNested().getNumWithDefault());
+
+    assertEquals(2,  deserialized.getOneofInner().getNum());
+    assertEquals(42,  deserialized.getOneofInner().getNumWithDefault());
+    assertEquals(3,  deserialized.getOneofInner().getNested().getNum());
+    assertEquals(4,  deserialized.getOneofInner().getNested().getNumWithDefault());
+
+    assertEquals(bytes, deserialized.toByteString());
+  }
+
+  public void testLaziness() throws InvalidProtocolBufferException {
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(2)
+        .build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .setInner(inner)
+        .setOneofInner(inner)
+        .build();
+    ByteString bytes = outer.toByteString();
+
+
+    // The parser for inner / oneofInner message shouldn't be used if
+    // getInner / getOneofInner is not called.
+    LazyInnerMessageLite.PARSER = EasyMock.createStrictMock(Parser.class);
+
+    EasyMock.replay(LazyInnerMessageLite.PARSER);
+
+    LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
+    assertEquals(1, deserialized.getNum());
+    assertEquals(421,  deserialized.getNumWithDefault());
+
+    EasyMock.verify(LazyInnerMessageLite.PARSER);
+  }
+}

+ 12 - 0
java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java

@@ -67,6 +67,14 @@ public class LazyStringArrayListTest extends TestCase {
     list.remove(1);
     assertSame(STRING_A, list.get(0));
     assertSame(STRING_C, list.get(1));
+
+    List<ByteString> byteStringList = list.asByteStringList();
+    assertEquals(BYTE_STRING_A, byteStringList.get(0));
+    assertEquals(BYTE_STRING_C, byteStringList.get(1));
+
+    // Underlying list should be transformed.
+    assertSame(byteStringList.get(0), list.getByteString(0));
+    assertSame(byteStringList.get(1), list.getByteString(1));
   }
 
   public void testJustByteString() {
@@ -83,6 +91,10 @@ public class LazyStringArrayListTest extends TestCase {
     list.remove(1);
     assertSame(BYTE_STRING_A, list.getByteString(0));
     assertSame(BYTE_STRING_C, list.getByteString(1));
+
+    List<ByteString> byteStringList = list.asByteStringList();
+    assertSame(BYTE_STRING_A, byteStringList.get(0));
+    assertSame(BYTE_STRING_C, byteStringList.get(1));
   }
 
   public void testConversionBackAndForth() {

+ 85 - 0
java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java

@@ -0,0 +1,85 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+
+import junit.framework.TestCase;
+
+/**
+ * Test generate equal and hash methods for the lite runtime.
+ *
+ * @author pbogle@google.com Phil Bogle
+ */
+public class LiteEqualsAndHashTest extends TestCase {
+
+  public void testEquals() throws Exception {
+    // Since the generated equals and hashCode methods for lite messages are a
+    // mostly complete subset of those for regular messages, we can mostly assume
+    // that the generated methods are already thoroughly tested by the regular tests.
+
+    // This test mostly just verifies is that a proto with
+    // optimize_for = LITE_RUNTIME and java_generates_equals_and_hash_compiles
+    // correctly when linked only against the lite library.
+
+    // We do however do some basic testing to make sure that equals is actually
+    // overriden to test for value equality rather than simple object equality.
+
+    // Check that two identical objs are equal.
+    Foo foo1a = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo1"))
+        .build();
+    Foo foo1b = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo1"))
+        .build();
+    Foo foo2 = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo2"))
+        .build();
+
+    // Check that equals is doing value rather than object equality.
+    assertEquals(foo1a, foo1b);
+    assertEquals(foo1a.hashCode(), foo1b.hashCode());
+
+    // Check that a diffeent object is not equal.
+    assertFalse(foo1a.equals(foo2));
+
+    // Check that two objects which have different types but the same field values are not
+    // considered to be equal.
+    Bar bar = Bar.newBuilder().setName("bar").build();
+    BarPrime barPrime = BarPrime.newBuilder().setName("bar").build();
+    assertFalse(bar.equals(barPrime));
+  }
+}

+ 15 - 9
java/src/test/java/com/google/protobuf/ParserTest.java

@@ -33,15 +33,14 @@ package com.google.protobuf;
 import com.google.protobuf.UnittestLite.TestAllTypesLite;
 import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
 import com.google.protobuf.UnittestLite.TestParsingMergeLite;
-import com.google.protobuf.UnittestLite;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
 import protobuf_unittest.UnittestOptimizeFor;
 import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
-import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestParsingMerge;
+import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto;
 
 import junit.framework.TestCase;
@@ -84,12 +83,15 @@ public class ParserTest extends TestCase {
         CodedInputStream.newInstance(data), registry));
   }
 
+  @SuppressWarnings("unchecked")
   private void assertRoundTripEquals(MessageLite message) throws Exception {
     final byte[] data = message.toByteArray();
     final int offset = 20;
     final int length = data.length;
     final int padding = 30;
-    Parser<? extends MessageLite> parser = message.getParserForType();
+
+    Parser<MessageLite> parser =
+        (Parser<MessageLite>) message.getParserForType();
     assertMessageEquals(message, parser.parseFrom(data));
     assertMessageEquals(message, parser.parseFrom(
         generatePaddingArray(data, offset, padding),
@@ -101,7 +103,8 @@ public class ParserTest extends TestCase {
         CodedInputStream.newInstance(data)));
   }
 
-  private void assertMessageEquals(MessageLite expected, MessageLite actual)
+  private void assertMessageEquals(
+      MessageLite expected, MessageLite actual)
       throws Exception {
     if (expected instanceof Message) {
       assertEquals(expected, actual);
@@ -120,15 +123,17 @@ public class ParserTest extends TestCase {
     assertRoundTripEquals(TestUtil.getAllSet());
   }
 
+
   public void testParsePartial() throws Exception {
-    Parser<TestRequired> parser = TestRequired.PARSER;
+    assertParsePartial(TestRequired.PARSER,
+        TestRequired.newBuilder().setA(1).buildPartial());
+  }
+
+  private <T extends MessageLite> void assertParsePartial(
+      Parser<T> parser, T partialMessage) throws Exception {
     final String errorString =
         "Should throw exceptions when the parsed message isn't initialized.";
 
-    // TestRequired.b and TestRequired.c are not set.
-    TestRequired partialMessage = TestRequired.newBuilder()
-        .setA(1).buildPartial();
-
     // parsePartialFrom should pass.
     byte[] data = partialMessage.toByteArray();
     assertEquals(partialMessage, parser.parsePartialFrom(data));
@@ -218,6 +223,7 @@ public class ParserTest extends TestCase {
         emptyMessage.toByteString());
   }
 
+
   public void testOptimizeForSize() throws Exception {
     TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
     builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());

+ 33 - 0
java/src/test/java/com/google/protobuf/TestBadIdentifiers.java

@@ -60,4 +60,37 @@ public class TestBadIdentifiers extends TestCase {
         .Descriptor.NestedDescriptor.getDefaultInstance()
         .getDescriptorForType();
   }
+
+  public void testConflictingFieldNames() throws Exception {
+    TestBadIdentifiersProto.TestConflictingFieldNames message =
+        TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
+    // Make sure generated accessors are properly named.
+    assertEquals(0, message.getInt32Field1Count());
+    assertEquals(0, message.getEnumField2Count());
+    assertEquals(0, message.getStringField3Count());
+    assertEquals(0, message.getBytesField4Count());
+    assertEquals(0, message.getMessageField5Count());
+
+    assertEquals(0, message.getInt32FieldCount11());
+    assertEquals(1, message.getEnumFieldCount12().getNumber());
+    assertEquals("", message.getStringFieldCount13());
+    assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
+    assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
+
+    assertEquals(0, message.getInt32Field21Count());
+    assertEquals(0, message.getEnumField22Count());
+    assertEquals(0, message.getStringField23Count());
+    assertEquals(0, message.getBytesField24Count());
+    assertEquals(0, message.getMessageField25Count());
+
+    assertEquals(0, message.getInt32Field1List().size());
+    assertEquals(0, message.getInt32FieldList31());
+
+    assertEquals(0, message.getInt64FieldCount());
+    assertEquals(0L, message.getExtension(
+        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
+    assertEquals(0L, message.getExtension(
+        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
+
+  }
 }

+ 172 - 3
java/src/test/java/com/google/protobuf/TestUtil.java

@@ -56,6 +56,11 @@ import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
 import static protobuf_unittest.UnittestProto.defaultCordExtension;
 
+import static protobuf_unittest.UnittestProto.oneofUint32Extension;
+import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.oneofStringExtension;
+import static protobuf_unittest.UnittestProto.oneofBytesExtension;
+
 import static protobuf_unittest.UnittestProto.optionalInt32Extension;
 import static protobuf_unittest.UnittestProto.optionalInt64Extension;
 import static protobuf_unittest.UnittestProto.optionalUint32Extension;
@@ -148,6 +153,11 @@ import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
 import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
 import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
 
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+
 import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
 import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
 import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
@@ -223,6 +233,7 @@ import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
@@ -469,6 +480,12 @@ public final class TestUtil {
 
     message.setDefaultStringPiece("424");
     message.setDefaultCord("425");
+
+    message.setOneofUint32(601);
+    message.setOneofNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
+    message.setOneofString("603");
+    message.setOneofBytes(toBytes("604"));
   }
 
   // -------------------------------------------------------------------
@@ -718,6 +735,13 @@ public final class TestUtil {
 
     Assert.assertEquals("424", message.getDefaultStringPiece());
     Assert.assertEquals("425", message.getDefaultCord());
+
+    Assert.assertFalse(message.hasOneofUint32());
+    Assert.assertFalse(message.hasOneofNestedMessage());
+    Assert.assertFalse(message.hasOneofString());
+    Assert.assertTrue(message.hasOneofBytes());
+
+    Assert.assertEquals(toBytes("604"), message.getOneofBytes());
   }
 
   // -------------------------------------------------------------------
@@ -872,6 +896,11 @@ public final class TestUtil {
 
     Assert.assertEquals("abc", message.getDefaultStringPiece());
     Assert.assertEquals("123", message.getDefaultCord());
+
+    Assert.assertFalse(message.hasOneofUint32());
+    Assert.assertFalse(message.hasOneofNestedMessage());
+    Assert.assertFalse(message.hasOneofString());
+    Assert.assertFalse(message.hasOneofBytes());
   }
 
   // -------------------------------------------------------------------
@@ -1358,6 +1387,12 @@ public final class TestUtil {
 
     message.setExtension(defaultStringPieceExtension, "424");
     message.setExtension(defaultCordExtension, "425");
+
+    message.setExtension(oneofUint32Extension, 601);
+    message.setExtension(oneofNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
+    message.setExtension(oneofStringExtension, "603");
+    message.setExtension(oneofBytesExtension, toBytes("604"));
   }
 
   // -------------------------------------------------------------------
@@ -1621,6 +1656,10 @@ public final class TestUtil {
 
     assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension));
     assertEqualsExactType("425", message.getExtension(defaultCordExtension));
+
+    Assert.assertTrue(message.hasExtension(oneofBytesExtension));
+
+    assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtension));
   }
 
   // -------------------------------------------------------------------
@@ -1807,6 +1846,11 @@ public final class TestUtil {
 
     assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension));
     assertEqualsExactType("123", message.getExtension(defaultCordExtension));
+
+    Assert.assertFalse(message.hasExtension(oneofUint32Extension));
+    Assert.assertFalse(message.hasExtension(oneofNestedMessageExtension));
+    Assert.assertFalse(message.hasExtension(oneofStringExtension));
+    Assert.assertFalse(message.hasExtension(oneofBytesExtension));
   }
 
   // -------------------------------------------------------------------
@@ -2133,6 +2177,12 @@ public final class TestUtil {
 
     message.setExtension(defaultStringPieceExtensionLite, "424");
     message.setExtension(defaultCordExtensionLite, "425");
+
+    message.setExtension(oneofUint32ExtensionLite, 601);
+    message.setExtension(oneofNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+    message.setExtension(oneofStringExtensionLite, "603");
+    message.setExtension(oneofBytesExtensionLite, toBytes("604"));
   }
 
   // -------------------------------------------------------------------
@@ -2397,6 +2447,10 @@ public final class TestUtil {
 
     assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite));
     assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite));
+
+    Assert.assertTrue(message.hasExtension(oneofBytesExtensionLite));
+
+    assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtensionLite));
   }
 
   // -------------------------------------------------------------------
@@ -2562,6 +2616,11 @@ public final class TestUtil {
 
     assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite));
     assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite));
+
+    Assert.assertFalse(message.hasExtension(oneofUint32ExtensionLite));
+    Assert.assertFalse(message.hasExtension(oneofNestedMessageExtensionLite));
+    Assert.assertFalse(message.hasExtension(oneofStringExtensionLite));
+    Assert.assertFalse(message.hasExtension(oneofBytesExtensionLite));
   }
 
   // -------------------------------------------------------------------
@@ -2749,6 +2808,82 @@ public final class TestUtil {
                           message.getExtension(packedEnumExtensionLite, 1));
   }
 
+  // ===================================================================
+  // oneof
+  public static void setOneof(TestOneof2.Builder message) {
+    message.setFooLazyMessage(
+        TestOneof2.NestedMessage.newBuilder().setQuxInt(100).build());
+    message.setBarString("101");
+    message.setBazInt(102);
+    message.setBazString("103");
+  }
+
+  public static void assertOneofSet(TestOneof2 message) {
+    Assert.assertTrue(message.hasFooLazyMessage            ());
+    Assert.assertTrue(message.getFooLazyMessage().hasQuxInt());
+
+    Assert.assertTrue(message.hasBarString());
+    Assert.assertTrue(message.hasBazInt   ());
+    Assert.assertTrue(message.hasBazString());
+
+    Assert.assertEquals(100  , message.getFooLazyMessage().getQuxInt());
+    Assert.assertEquals("101", message.getBarString                 ());
+    Assert.assertEquals(102  , message.getBazInt                    ());
+    Assert.assertEquals("103", message.getBazString                 ());
+  }
+
+  public static void assertAtMostOneFieldSetOneof(TestOneof2 message) {
+    int count = 0;
+    if (message.hasFooInt()) { ++count; }
+    if (message.hasFooString()) { ++count; }
+    if (message.hasFooCord()) { ++count; }
+    if (message.hasFooStringPiece()) { ++count; }
+    if (message.hasFooBytes()) { ++count; }
+    if (message.hasFooEnum()) { ++count; }
+    if (message.hasFooMessage()) { ++count; }
+    if (message.hasFooGroup()) { ++count; }
+    if (message.hasFooLazyMessage()) { ++count; }
+    Assert.assertTrue(count <= 1);
+
+    count = 0;
+    if (message.hasBarInt()) { ++count; }
+    if (message.hasBarString()) { ++count; }
+    if (message.hasBarCord()) { ++count; }
+    if (message.hasBarStringPiece()) { ++count; }
+    if (message.hasBarBytes()) { ++count; }
+    if (message.hasBarEnum()) { ++count; }
+    Assert.assertTrue(count <= 1);
+
+    switch (message.getFooCase()) {
+      case FOO_INT:
+        Assert.assertTrue(message.hasFooInt());
+        break;
+      case FOO_STRING:
+        Assert.assertTrue(message.hasFooString());
+        break;
+      case FOO_CORD:
+        Assert.assertTrue(message.hasFooCord());
+        break;
+      case FOO_BYTES:
+        Assert.assertTrue(message.hasFooBytes());
+        break;
+      case FOO_ENUM:
+        Assert.assertTrue(message.hasFooEnum());
+        break;
+      case FOO_MESSAGE:
+        Assert.assertTrue(message.hasFooMessage());
+        break;
+      case FOOGROUP:
+        Assert.assertTrue(message.hasFooGroup());
+        break;
+      case FOO_LAZY_MESSAGE:
+        Assert.assertTrue(message.hasFooLazyMessage());
+        break;
+      case FOO_NOT_SET:
+        break;
+    }
+  }
+
   // =================================================================
 
   /**
@@ -2915,8 +3050,8 @@ public final class TestUtil {
         return parent.newBuilderForField(field);
       } else {
         ExtensionRegistry.ExtensionInfo extension =
-          extensionRegistry.findExtensionByNumber(field.getContainingType(),
-                                                  field.getNumber());
+          extensionRegistry.findImmutableExtensionByNumber(
+              field.getContainingType(), field.getNumber());
         Assert.assertNotNull(extension);
         Assert.assertNotNull(extension.defaultInstance);
         return extension.defaultInstance.newBuilderForType();
@@ -3078,6 +3213,13 @@ public final class TestUtil {
 
       message.setField(f("default_string_piece" ), "424");
       message.setField(f("default_cord" ), "425");
+
+      message.setField(f("oneof_uint32" ), 601);
+      message.setField(f("oneof_nested_message"),
+        newBuilderForField(message, f("oneof_nested_message"))
+          .setField(nestedB, 602).build());
+      message.setField(f("oneof_string" ), "603");
+      message.setField(f("oneof_bytes" ), toBytes("604"));
     }
 
     // -------------------------------------------------------------------
@@ -3372,6 +3514,24 @@ public final class TestUtil {
 
       Assert.assertEquals("424", message.getField(f("default_string_piece")));
       Assert.assertEquals("425", message.getField(f("default_cord")));
+
+      Assert.assertTrue(message.hasField(f("oneof_bytes")));
+      Assert.assertEquals(toBytes("604"), message.getField(f("oneof_bytes")));
+
+      if (extensionRegistry == null) {
+        Assert.assertFalse(message.hasField(f("oneof_uint32")));
+        Assert.assertFalse(message.hasField(f("oneof_nested_message")));
+        Assert.assertFalse(message.hasField(f("oneof_string")));
+      } else {
+        Assert.assertTrue(message.hasField(f("oneof_uint32")));
+        Assert.assertTrue(message.hasField(f("oneof_nested_message")));
+        Assert.assertTrue(message.hasField(f("oneof_string")));
+        Assert.assertEquals(601, message.getField(f("oneof_uint32")));
+        Assert.assertEquals(602,
+            ((MessageOrBuilder) message.getField(f("oneof_nested_message")))
+            .getField(nestedB));
+        Assert.assertEquals("603", message.getField(f("oneof_string")));
+      }
     }
 
     // -------------------------------------------------------------------
@@ -3549,6 +3709,15 @@ public final class TestUtil {
 
       Assert.assertEquals("abc", message.getField(f("default_string_piece")));
       Assert.assertEquals("123", message.getField(f("default_cord")));
+
+      Assert.assertFalse(message.hasField(f("oneof_uint32")));
+      Assert.assertFalse(message.hasField(f("oneof_nested_message")));
+      Assert.assertFalse(message.hasField(f("oneof_string")));
+      Assert.assertFalse(message.hasField(f("oneof_bytes")));
+
+      Assert.assertEquals(0, message.getField(f("oneof_uint32")));
+      Assert.assertEquals("", message.getField(f("oneof_string")));
+      Assert.assertEquals(toBytes(""), message.getField(f("oneof_bytes")));
     }
 
 
@@ -3910,7 +4079,7 @@ public final class TestUtil {
    */
   public static ByteString getGoldenMessage() {
     if (goldenMessage == null) {
-      goldenMessage = readBytesFromFile("golden_message");
+      goldenMessage = readBytesFromFile("golden_message_oneof_implemented");
     }
     return goldenMessage;
   }

+ 318 - 7
java/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -31,6 +31,7 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
 import protobuf_unittest.UnittestMset.TestMessageSet;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
@@ -39,6 +40,7 @@ import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestOneof2;
 
 import junit.framework.TestCase;
 
@@ -64,7 +66,7 @@ public class TextFormatTest extends TestCase {
           + "and \\t tabs and \\001 slashes \\\\";
 
   private static String allFieldsSetText = TestUtil.readTextFromFile(
-    "text_format_unittest_data.txt");
+    "text_format_unittest_data_oneof_implemented.txt");
   private static String allExtensionsSetText = TestUtil.readTextFromFile(
     "text_format_unittest_extensions_data.txt");
 
@@ -109,6 +111,26 @@ public class TextFormatTest extends TestCase {
     "  str: \"foo\"\n" +
     "}\n";
 
+  private String messageSetTextWithRepeatedExtension =
+      "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+      "  i: 123\n" +
+      "}\n" +
+      "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+      "  i: 456\n" +
+      "}\n";
+
+  private final TextFormat.Parser parserAllowingUnknownFields =
+      TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build();
+
+  private final TextFormat.Parser parserWithOverwriteForbidden =
+      TextFormat.Parser.newBuilder()
+          .setSingularOverwritePolicy(
+              SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+          .build();
+
+  private final TextFormat.Parser defaultParser =
+      TextFormat.Parser.newBuilder().build();
+
   /** Print TestAllTypes and compare with golden file. */
   public void testPrintMessage() throws Exception {
     String javaText = TextFormat.printToString(TestUtil.getAllSet());
@@ -250,8 +272,8 @@ public class TextFormatTest extends TestCase {
 
       .addRepeatedInt32 (1  << 31)
       .addRepeatedUint32(1  << 31)
-      .addRepeatedInt64 (1l << 63)
-      .addRepeatedUint64(1l << 63)
+      .addRepeatedInt64 (1L << 63)
+      .addRepeatedUint64(1L << 63)
 
       // Floats of various precisions and exponents.
       .addRepeatedDouble(123)
@@ -371,6 +393,40 @@ public class TextFormatTest extends TestCase {
       TestMessageSetExtension2.messageSetExtension));
     assertEquals("foo", messageSet.getExtension(
       TestMessageSetExtension2.messageSetExtension).getStr());
+
+    builder = TestMessageSet.newBuilder();
+    TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry,
+        builder);
+    messageSet = builder.build();
+    assertEquals(456, messageSet.getExtension(
+      TestMessageSetExtension1.messageSetExtension).getI());
+  }
+
+  public void testParseMessageSetWithOverwriteForbidden() throws Exception {
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+    TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+    parserWithOverwriteForbidden.merge(
+        messageSetText, extensionRegistry, builder);
+    TestMessageSet messageSet = builder.build();
+    assertEquals(123, messageSet.getExtension(
+        TestMessageSetExtension1.messageSetExtension).getI());
+    assertEquals("foo", messageSet.getExtension(
+      TestMessageSetExtension2.messageSetExtension).getStr());
+
+    builder = TestMessageSet.newBuilder();
+    try {
+      parserWithOverwriteForbidden.merge(
+          messageSetTextWithRepeatedExtension, extensionRegistry, builder);
+      fail("expected parse exception");
+    } catch (TextFormat.ParseException e) {
+      assertEquals("6:1: Non-repeated field "
+          + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
+          + " cannot be overwritten.",
+          e.getMessage());
+    }
   }
 
   public void testParseNumericEnum() throws Exception {
@@ -407,12 +463,51 @@ public class TextFormatTest extends TestCase {
     }
   }
 
+  private void assertParseErrorWithUnknownFields(String error, String text) {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      parserAllowingUnknownFields.merge(
+          text, TestUtil.getExtensionRegistry(), builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
+  }
+
+  private TestAllTypes assertParseSuccessWithUnknownFields(String text)
+      throws TextFormat.ParseException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    parserAllowingUnknownFields.merge(
+        text, TestUtil.getExtensionRegistry(), builder);
+    return builder.build();
+  }
+
+  private void assertParseErrorWithOverwriteForbidden(String error,
+      String text) {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      parserWithOverwriteForbidden.merge(
+          text, TestUtil.getExtensionRegistry(), builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
+  }
+
+  private TestAllTypes assertParseSuccessWithOverwriteForbidden(
+      String text) throws TextFormat.ParseException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    parserWithOverwriteForbidden.merge(
+        text, TestUtil.getExtensionRegistry(), builder);
+    return builder.build();
+  }
+
   public void testParseErrors() throws Exception {
     assertParseError(
       "1:16: Expected \":\".",
       "optional_int32 123");
     assertParseError(
-      "1:23: Expected identifier.",
+      "1:23: Expected identifier. Found '?'",
       "optional_nested_enum: ?");
     assertParseError(
       "1:18: Couldn't parse integer: Number must be positive: -1",
@@ -469,10 +564,10 @@ public class TextFormatTest extends TestCase {
 
     // Delimiters must match.
     assertParseError(
-      "1:22: Expected identifier.",
+      "1:22: Expected identifier. Found '}'",
       "OptionalGroup < a: 1 }");
     assertParseError(
-      "1:22: Expected identifier.",
+      "1:22: Expected identifier. Found '>'",
       "OptionalGroup { a: 1 >");
   }
 
@@ -762,7 +857,7 @@ public class TextFormatTest extends TestCase {
         TextFormat.shortDebugString(makeUnknownFieldSet()));
   }
 
-  public void testPrintToUnicodeString() {
+  public void testPrintToUnicodeString() throws Exception {
     assertEquals(
         "optional_string: \"abc\u3042efg\"\n" +
         "optional_bytes: \"\\343\\201\\202\"\n" +
@@ -772,6 +867,49 @@ public class TextFormatTest extends TestCase {
             .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
             .addRepeatedString("\u3093XYZ")
             .build()));
+
+    // Double quotes and backslashes should be escaped
+    assertEquals(
+        "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("a\\bc\"ef\"g")
+            .build()));
+
+    // Test escaping roundtrip
+    TestAllTypes message = TestAllTypes.newBuilder()
+        .setOptionalString("a\\bc\\\"ef\"g")
+        .build();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+    assertEquals(message.getOptionalString(), builder.getOptionalString());
+  }
+  
+  public void testPrintToUnicodeStringWithNewlines() {
+    // No newlines at start and end
+    assertEquals("optional_string: \"test newlines\n\nin\nstring\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("test newlines\n\nin\nstring")
+            .build()));
+
+    // Newlines at start and end
+    assertEquals("optional_string: \"\ntest\nnewlines\n\nin\nstring\n\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+            .build()));
+
+    // Strings with 0, 1 and 2 newlines.
+    assertEquals("optional_string: \"\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("")
+            .build()));
+    assertEquals("optional_string: \"\n\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("\n")
+            .build()));
+    assertEquals("optional_string: \"\n\n\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("\n\n")
+            .build()));
   }
 
   public void testPrintToUnicodeString_unknown() {
@@ -783,4 +921,177 @@ public class TextFormatTest extends TestCase {
                 .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build())
             .build()));
   }
+
+  public void testParseUnknownFields() throws Exception {
+    assertParseSuccessWithUnknownFields("unknown_field: 12345");
+    assertParseSuccessWithUnknownFields("unknown_field: -12345");
+    assertParseSuccessWithUnknownFields("unknown_field: 1.2345");
+    assertParseSuccessWithUnknownFields("unknown_field: -1.2345");
+    assertParseSuccessWithUnknownFields("unknown_field: 1.2345f");
+    assertParseSuccessWithUnknownFields("unknown_field: -1.2345f");
+    assertParseSuccessWithUnknownFields("unknown_field: inf");
+    assertParseSuccessWithUnknownFields("unknown_field: -inf");
+    assertParseSuccessWithUnknownFields("unknown_field: TYPE_STRING");
+    assertParseSuccessWithUnknownFields("unknown_field: \"string value\"");
+    // Invalid field value
+    assertParseErrorWithUnknownFields(
+        "1:16: Invalid field value: -TYPE_STRING",
+        "unknown_field: -TYPE_STRING");
+    // Two or more unknown fields
+    assertParseSuccessWithUnknownFields("unknown_field1: TYPE_STRING\n" +
+                                        "unknown_field2: 12345");
+    // Unknown nested message
+    assertParseSuccessWithUnknownFields("unknown_message1: {}\n" +
+                                        "unknown_message2 {\n" +
+                                        "  unknown_field: 12345\n" +
+                                        "}\n" +
+                                        "unknown_message3 <\n" +
+                                        "  unknown_nested_message {\n" +
+                                        "    unknown_field: 12345\n" +
+                                        "  }\n" +
+                                        ">");
+    // Unmatched delimeters for message body
+    assertParseErrorWithUnknownFields(
+        "1:19: Expected \"}\".", "unknown_message: {>");
+    // Unknown extension
+    assertParseSuccessWithUnknownFields(
+        "[somewhere.unknown_extension1]: 12345\n" +
+        "[somewhere.unknown_extension2] {\n" +
+        "  unknown_field: 12345\n" +
+        "}");
+    // Unknown fields between known fields.
+    TestAllTypes expected = TestAllTypes.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalString("string")
+        .setOptionalNestedMessage(NestedMessage.newBuilder()
+            .setBb(2))
+        .build();
+    assertEquals(expected, assertParseSuccessWithUnknownFields(
+        "optional_int32: 1\n" +
+        "unknown_field: 12345\n" +
+        "optional_string: \"string\"\n" +
+        "unknown_message { unknown : 0 }\n" +
+        "optional_nested_message { bb: 2 }"));
+    // Nested unknown extensions.
+    assertParseSuccessWithUnknownFields(
+        "[test.extension1] <\n" +
+        "  unknown_nested_message <\n" +
+        "    [test.extension2] <\n" +
+        "      unknown_field: 12345\n" +
+        "    >\n" +
+        "  >\n" +
+        ">");
+    assertParseSuccessWithUnknownFields(
+        "[test.extension1] {\n" +
+        "  unknown_nested_message {\n" +
+        "    [test.extension2] {\n" +
+        "      unknown_field: 12345\n" +
+        "    }\n" +
+        "  }\n" +
+        "}");
+    assertParseSuccessWithUnknownFields(
+        "[test.extension1] <\n" +
+        "  some_unknown_fields: <\n" +
+        "    unknown_field: 12345\n" +
+        "  >\n" +
+        ">");
+    assertParseSuccessWithUnknownFields(
+        "[test.extension1] {\n" +
+        "  some_unknown_fields: {\n" +
+        "    unknown_field: 12345\n" +
+        "  }\n" +
+        "}");
+  }
+
+  public void testParseNonRepeatedFields() throws Exception {
+    assertParseSuccessWithOverwriteForbidden(
+        "repeated_int32: 1\n" +
+        "repeated_int32: 2\n");
+    assertParseSuccessWithOverwriteForbidden(
+        "RepeatedGroup { a: 1 }\n" +
+        "RepeatedGroup { a: 2 }\n");
+    assertParseSuccessWithOverwriteForbidden(
+        "repeated_nested_message { bb: 1 }\n" +
+        "repeated_nested_message { bb: 2 }\n");
+    assertParseErrorWithOverwriteForbidden(
+        "3:17: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.optional_int32\" " +
+        "cannot be overwritten.",
+        "optional_int32: 1\n" +
+        "optional_bool: true\n" +
+        "optional_int32: 1\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:17: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.optionalgroup\" " +
+        "cannot be overwritten.",
+        "OptionalGroup { a: 1 }\n" +
+        "OptionalGroup { }\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:33: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " +
+        "cannot be overwritten.",
+        "optional_nested_message { }\n" +
+        "optional_nested_message { bb: 3 }\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:16: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.default_int32\" " +
+        "cannot be overwritten.",
+        "default_int32: 41\n" +  // the default value
+        "default_int32: 41\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:17: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.default_string\" " +
+        "cannot be overwritten.",
+        "default_string: \"zxcv\"\n" +
+        "default_string: \"asdf\"\n");
+  }
+
+  public void testParseShortRepeatedFormOfRepeatedFields() throws Exception {
+    assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]");
+    assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
+    assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
+    assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
+  }
+
+  public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
+    assertParseErrorWithOverwriteForbidden(
+        "1:17: Couldn't parse integer: For input string: \"[\"",
+        "optional_int32: [1]\n");
+  }
+
+  // =======================================================================
+  // test oneof
+
+  public void testOneofTextFormat() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestUtil.setOneof(builder);
+    TestOneof2 message = builder.build();
+    TestOneof2.Builder dest = TestOneof2.newBuilder();
+    TextFormat.merge(TextFormat.printToUnicodeString(message), dest);
+    TestUtil.assertOneofSet(dest.build());
+  }
+
+  public void testOneofOverwriteForbidden() throws Exception {
+    String input = "foo_string: \"stringvalue\" foo_int: 123";
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    try {
+      parserWithOverwriteForbidden.merge(
+          input, TestUtil.getExtensionRegistry(), builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
+                   + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
+                   + " another member of oneof \"foo\".", e.getMessage());
+    }
+  }
+
+  public void testOneofOverwriteAllowed() throws Exception {
+    String input = "foo_string: \"stringvalue\" foo_int: 123";
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder);
+    // Only the last value sticks.
+    TestOneof2 oneof = builder.build();
+    assertFalse(oneof.hasFooString());
+    assertTrue(oneof.hasFooInt());
+  }
 }

+ 216 - 0
java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java

@@ -31,10 +31,13 @@
 package com.google.protobuf;
 
 import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
 
 import junit.framework.TestCase;
 
@@ -204,6 +207,13 @@ public class UnknownFieldSetTest extends TestCase {
       TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
     assertEquals(0, message.getSerializedSize());
   }
+  
+  public void testClearField() throws Exception {
+    int fieldNumber = unknownFields.asMap().keySet().iterator().next();
+    UnknownFieldSet fields =
+        UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
+    assertFalse(fields.hasField(fieldNumber));
+  }
 
   public void testParseKnownAndUnknown() throws Exception {
     // Test mixing known and unknown fields when parsing.
@@ -434,4 +444,210 @@ public class UnknownFieldSetTest extends TestCase {
     assertEquals(copy, set);
     assertEquals(set.hashCode(), copy.hashCode());
   }
+
+  // =================================================================
+
+  public void testSerializeLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllTypes message = TestAllTypes.parseFrom(data);
+    TestUtil.assertAllFieldsSet(message);
+    assertEquals(allFieldsData, data);
+  }
+
+  public void testAllExtensionsLite() throws Exception {
+    TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
+    ByteString allExtensionsData = allExtensions.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.PARSER.parseFrom(allExtensionsData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllExtensions message =
+        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertAllExtensionsSet(message);
+    assertEquals(allExtensionsData, data);
+  }
+
+  public void testAllPackedFieldsLite() throws Exception {
+    TestPackedTypes allPackedFields = TestUtil.getPackedSet();
+    ByteString allPackedData = allPackedFields.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestPackedTypes message =
+        TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertPackedFieldsSet(message);
+    assertEquals(allPackedData, data);
+  }
+
+  public void testAllPackedExtensionsLite() throws Exception {
+    TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
+    ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestPackedExtensions message =
+        TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertPackedExtensionsSet(message);
+    assertEquals(allPackedExtensionsData, data);
+  }
+
+  public void testCopyFromLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.newBuilder()
+        .mergeFrom(emptyMessageLite).build();
+    assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
+  }
+
+  public void testMergeFromLite() throws Exception {
+    TestAllTypes message1 = TestAllTypes.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalString("foo")
+        .addRepeatedString("bar")
+        .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
+        .build();
+
+    TestAllTypes message2 = TestAllTypes.newBuilder()
+        .setOptionalInt64(2)
+        .setOptionalString("baz")
+        .addRepeatedString("qux")
+        .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
+        .build();
+
+    ByteString data1 = message1.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data1);
+    ByteString data2 = message2.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data2);
+
+    message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
+    emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
+                        .mergeFrom(emptyMessageLite2).build();
+
+    data1 = emptyMessageLite1.toByteString();
+    message2 = TestAllTypes.parseFrom(data1);
+
+    assertEquals(message1, message2);
+  }
+
+  public void testWrongTypeTreatedAsUnknownLite() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
+
+    assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
+  }
+
+  public void testUnknownExtensionsLite() throws Exception {
+    // Make sure fields are properly parsed to the UnknownFieldSet even when
+    // they are declared as extension numbers.
+
+    UnittestLite.TestEmptyMessageWithExtensionsLite message =
+      UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
+
+    assertEquals(allFieldsData, message.toByteString());
+  }
+
+  public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing extensions.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllExtensions allExtensionsMessage =
+      TestAllExtensions.parseFrom(bizarroData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the byte strings
+    // should be the same.
+    assertEquals(emptyMessageLite.toByteString(),
+                 allExtensionsMessage.toByteString());
+  }
+
+  public void testParseUnknownEnumValueLite() throws Exception {
+    Descriptors.FieldDescriptor singularField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+    Descriptors.FieldDescriptor repeatedField =
+      TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+    assertNotNull(singularField);
+    assertNotNull(repeatedField);
+
+    ByteString data =
+      UnknownFieldSet.newBuilder()
+        .addField(singularField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+            .addVarint(5)   // not valid
+            .build())
+        .addField(repeatedField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+            .addVarint(4)   // not valid
+            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+            .addVarint(6)   // not valid
+            .build())
+        .build()
+        .toByteString();
+
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data);
+    data = emptyMessageLite.toByteString();
+
+    {
+      TestAllTypes message = TestAllTypes.parseFrom(data);
+      assertEquals(TestAllTypes.NestedEnum.BAR,
+                   message.getOptionalNestedEnum());
+      assertEquals(
+        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+        message.getRepeatedNestedEnumList());
+      assertEquals(Arrays.asList(5L),
+                   message.getUnknownFields()
+                          .getField(singularField.getNumber())
+                          .getVarintList());
+      assertEquals(Arrays.asList(4L, 6L),
+                   message.getUnknownFields()
+                          .getField(repeatedField.getNumber())
+                          .getVarintList());
+    }
+
+    {
+      TestAllExtensions message =
+        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+      assertEquals(TestAllTypes.NestedEnum.BAR,
+        message.getExtension(UnittestProto.optionalNestedEnumExtension));
+      assertEquals(
+        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+        message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+      assertEquals(Arrays.asList(5L),
+                   message.getUnknownFields()
+                          .getField(singularField.getNumber())
+                          .getVarintList());
+      assertEquals(Arrays.asList(4L, 6L),
+                   message.getUnknownFields()
+                          .getField(repeatedField.getNumber())
+                          .getVarintList());
+    }
+  }
+
+  public void testClearLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.newBuilder()
+        .mergeFrom(emptyMessageLite1).clear().build();
+    assertEquals(0, emptyMessageLite2.getSerializedSize());
+    ByteString data = emptyMessageLite2.toByteString();
+    assertEquals(0, data.size());
+  }
+
 }

+ 75 - 0
java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java

@@ -33,6 +33,7 @@ package com.google.protobuf;
 import junit.framework.TestCase;
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.ListIterator;
 
 /**
@@ -60,6 +61,11 @@ public class UnmodifiableLazyStringListTest extends TestCase {
     assertEquals(BYTE_STRING_A, list.getByteString(0));
     assertEquals(BYTE_STRING_B, list.getByteString(1));
     assertEquals(BYTE_STRING_C, list.getByteString(2));
+
+    List<ByteString> byteStringList = list.asByteStringList();
+    assertSame(list.getByteString(0), byteStringList.get(0));
+    assertSame(list.getByteString(1), byteStringList.get(1));
+    assertSame(list.getByteString(2), byteStringList.get(2));
   }
 
   public void testModifyMethods() {
@@ -88,6 +94,35 @@ public class UnmodifiableLazyStringListTest extends TestCase {
     } catch (UnsupportedOperationException e) {
       // expected
     }
+    assertEquals(3, list.size());
+
+    List<ByteString> byteStringList = list.asByteStringList();
+    try {
+      byteStringList.remove(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(3, list.size());
+    assertEquals(3, byteStringList.size());
+
+    try {
+      byteStringList.add(BYTE_STRING_B);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(3, list.size());
+    assertEquals(3, byteStringList.size());
+
+    try {
+      byteStringList.set(1, BYTE_STRING_B);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(3, list.size());
+    assertEquals(3, byteStringList.size());
   }
 
   public void testIterator() {
@@ -108,6 +143,20 @@ public class UnmodifiableLazyStringListTest extends TestCase {
     }
     assertEquals(3, count);
 
+    List<ByteString> byteStringList = list.asByteStringList();
+    Iterator<ByteString> byteIter = byteStringList.iterator();
+    count = 0;
+    while (byteIter.hasNext()) {
+      byteIter.next();
+      count++;
+      try {
+        byteIter.remove();
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+    }
+    assertEquals(3, count);
   }
 
   public void testListIterator() {
@@ -140,6 +189,32 @@ public class UnmodifiableLazyStringListTest extends TestCase {
     }
     assertEquals(3, count);
 
+    List<ByteString> byteStringList = list.asByteStringList();
+    ListIterator<ByteString> byteIter = byteStringList.listIterator();
+    count = 0;
+    while (byteIter.hasNext()) {
+      byteIter.next();
+      count++;
+      try {
+        byteIter.remove();
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+      try {
+        byteIter.set(BYTE_STRING_A);
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+      try {
+        byteIter.add(BYTE_STRING_A);
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+    }
+    assertEquals(3, count);
   }
 
   private LazyStringArrayList createSampleList() {

+ 28 - 2
java/src/test/java/com/google/protobuf/WireFormatTest.java

@@ -40,6 +40,8 @@ import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestFieldOrderings;
+import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestMset.TestMessageSet;
@@ -218,8 +220,8 @@ public class WireFormatTest extends TestCase {
   }
 
   public void testExtensionsSerializedSize() throws Exception {
-    assertEquals(TestUtil.getAllSet().getSerializedSize(),
-                 TestUtil.getAllExtensionsSet().getSerializedSize());
+    assertNotSame(TestUtil.getAllSet().getSerializedSize(),
+                  TestUtil.getAllExtensionsSet().getSerializedSize());
   }
 
   public void testSerializeDelimited() throws Exception {
@@ -577,4 +579,28 @@ public class WireFormatTest extends TestCase {
     assertEquals(123, messageSet.getExtension(
         TestMessageSetExtension1.messageSetExtension).getI());
   }
+
+  // ================================================================
+  // oneof
+  public void testOneofWireFormat() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestUtil.setOneof(builder);
+    TestOneof2 message = builder.build();
+    ByteString rawBytes = message.toByteString();
+
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
+    TestUtil.assertOneofSet(message2);
+  }
+
+  public void testOneofOnlyLastSet() throws Exception {
+    TestOneofBackwardsCompatible source = TestOneofBackwardsCompatible
+        .newBuilder().setFooInt(100).setFooString("101").build();
+
+    ByteString rawBytes = source.toByteString();
+    TestOneof2 message = TestOneof2.parseFrom(rawBytes);
+    assertFalse(message.hasFooInt());
+    assertTrue(message.hasFooString());
+  }
 }

+ 61 - 0
java/src/test/java/com/google/protobuf/lazy_fields_lite.proto

@@ -0,0 +1,61 @@
+// 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: Naoki Iwasaki (niwasaki@google.com)
+//
+// A proto file with lazy fields
+
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+message LazyMessageLite {
+  optional int32 num = 1;
+  optional int32 num_with_default = 2 [default = 421];
+  optional LazyInnerMessageLite inner = 3 [lazy = true];
+  repeated LazyInnerMessageLite repeated_inner = 4 [lazy = true];
+
+  oneof oneof_field {
+    int32 oneof_num = 5;
+    LazyInnerMessageLite oneof_inner = 6 [lazy = true];
+  }
+}
+
+message LazyInnerMessageLite {
+  optional int32 num = 1;
+  optional int32 num_with_default = 2 [default = 42];
+  optional LazyNestedInnerMessageLite nested = 3 [lazy = true];
+}
+
+message LazyNestedInnerMessageLite {
+  optional int32 num = 1;
+  optional int32 num_with_default = 2 [default = 4];
+}

+ 17 - 25
python/google/protobuf/pyext/python_protobuf.cc → java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto

@@ -28,36 +28,28 @@
 // (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: qrczak@google.com (Marcin Kowalczyk)
+// Author: pbogle@google.com (Phil Bogle)
 
-#include <google/protobuf/pyext/python_protobuf.h>
 
-namespace google {
-namespace protobuf {
-namespace python {
+package protobuf_unittest.lite_equals_and_hash;
 
-static const Message* GetCProtoInsidePyProtoStub(PyObject* msg) {
-  return NULL;
-}
-static Message* MutableCProtoInsidePyProtoStub(PyObject* msg) {
-  return NULL;
-}
+// This proto definition is used to test that java_generate_equals_and_hash
+// works correctly with the LITE_RUNTIME.
+option java_generate_equals_and_hash = true;
+option optimize_for = LITE_RUNTIME;
 
-// This is initialized with a default, stub implementation.
-// If python-google.protobuf.cc is loaded, the function pointer is overridden
-// with a full implementation.
-const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg) =
-    GetCProtoInsidePyProtoStub;
-Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg) =
-    MutableCProtoInsidePyProtoStub;
+message Foo {
+  optional int32 value = 1;
+  repeated Bar bar = 2;
+}
 
-const Message* GetCProtoInsidePyProto(PyObject* msg) {
-  return GetCProtoInsidePyProtoPtr(msg);
+message Bar {
+  optional string name = 1;
 }
-Message* MutableCProtoInsidePyProto(PyObject* msg) {
-  return MutableCProtoInsidePyProtoPtr(msg);
+
+message BarPrime {
+  optional string name = 1;
 }
 
-}  // namespace python
-}  // namespace protobuf
-}  // namespace google
+message Empty {
+}

+ 7 - 1
java/src/test/java/com/google/protobuf/multiple_files_test.proto

@@ -38,12 +38,14 @@
 option java_generic_services = true;   // auto-added
 
 import "google/protobuf/unittest.proto";
+import "google/protobuf/descriptor.proto";
 
 package protobuf_unittest;
 
 option java_multiple_files = true;
 option java_outer_classname = "MultipleFilesTestProto";
 
+
 message MessageWithNoOuter {
   message NestedMessage {
     optional int32 i = 1;
@@ -57,8 +59,12 @@ message MessageWithNoOuter {
   optional EnumWithNoOuter foreign_enum = 4;
 }
 
+extend google.protobuf.EnumValueOptions {
+  optional int32 enum_value_option = 7654321;
+}
+
 enum EnumWithNoOuter {
-  FOO = 1;
+  FOO = 1 [(enum_value_option) = 12345];
   BAR = 2;
 }
 

+ 1 - 0
java/src/test/java/com/google/protobuf/nested_extension.proto

@@ -38,6 +38,7 @@ import "com/google/protobuf/non_nested_extension.proto";
 
 package protobuf_unittest;
 
+
 message MyNestedExtension {
   extend MessageToBeExtended {
     optional MessageToBeExtended recursiveExtension = 2;

+ 1 - 0
java/src/test/java/com/google/protobuf/non_nested_extension.proto

@@ -35,6 +35,7 @@
 
 package protobuf_unittest;
 
+
 message MessageToBeExtended {
   extensions 1 to max;
 }

+ 38 - 0
java/src/test/java/com/google/protobuf/outer_class_name_test.proto

@@ -0,0 +1,38 @@
+// 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.
+
+package protobuf_unittest;
+
+
+// This message's name is the same with the default outer class name of this
+// proto file. It's used to test if the compiler can avoid this conflict
+// correctly.
+message OuterClassNameTest {
+}

+ 42 - 0
java/src/test/java/com/google/protobuf/outer_class_name_test2.proto

@@ -0,0 +1,42 @@
+// 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.
+
+package protobuf_unittest;
+
+
+message TestMessage2 {
+  message NestedMessage {
+    // This message's name is the same with the default outer class name of this
+    // proto file. It's used to test if the compiler can avoid this conflict
+    // correctly.
+    message OuterClassNameTest2 {
+    }
+  }
+}

+ 43 - 0
java/src/test/java/com/google/protobuf/outer_class_name_test3.proto

@@ -0,0 +1,43 @@
+// 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.
+
+package protobuf_unittest;
+
+
+message TestMessage3 {
+  message NestedMessage {
+    // This enum's name is the same with the default outer class name of this
+    // proto file. It's used to test if the compiler can avoid this conflict
+    // correctly.
+    enum OuterClassNameTest3 {
+      DUMMY_VALUE = 1;
+    }
+  }
+}

+ 49 - 0
java/src/test/java/com/google/protobuf/test_bad_identifiers.proto

@@ -42,8 +42,12 @@ package io_protocol_tests;
 
 option java_package = "com.google.protobuf";
 option java_outer_classname = "TestBadIdentifiersProto";
+option java_generate_equals_and_hash = true;
 
 message TestMessage {
+  optional string cached_size = 1;
+  optional string serialized_size = 2;
+  optional string class = 3;
 }
 
 message Descriptor {
@@ -54,6 +58,9 @@ message Descriptor {
     optional string descriptor = 1;
   }
   optional NestedDescriptor nested_descriptor = 2;
+  enum NestedEnum {
+    FOO = 1;
+  }
 }
 
 message Parser {
@@ -66,6 +73,9 @@ message Parser {
 message Deprecated {
   enum TestEnum {
     FOO = 1;
+
+    // Test if @Deprecated annotation conflicts with Deprecated message name.
+    BAR = 2 [ deprecated = true ];
   }
 
   optional int32 field1 = 1 [deprecated=true];
@@ -106,3 +116,42 @@ service TestConflictingMethodNames {
   rpc Override(TestMessage) returns (TestMessage);
 }
 
+message TestConflictingFieldNames {
+  enum TestEnum {
+    FOO = 1;
+  }
+  message TestMessage {
+  }
+  repeated int32 int32_field = 1;
+  repeated TestEnum enum_field = 2;
+  repeated string string_field = 3;
+  repeated bytes bytes_field = 4;
+  repeated TestMessage message_field = 5;
+
+  optional int32 int32_field_count = 11;
+  optional TestEnum enum_field_count = 12;
+  optional string string_field_count = 13;
+  optional bytes bytes_field_count = 14;
+  optional TestMessage message_field_count = 15;
+
+  repeated int32 Int32Field = 21;
+  repeated TestEnum EnumField = 22;
+  repeated string StringField = 23;
+  repeated bytes BytesField = 24;
+  repeated TestMessage MessageField = 25;
+
+  // This field conflicts with "int32_field" as they both generate
+  // the method getInt32FieldList().
+  required int32 int32_field_list = 31;
+
+  extensions 1000 to max;
+
+  repeated int64 int64_field = 41;
+  extend TestConflictingFieldNames {
+    // We don't generate accessors for extensions so the following extension
+    // fields don't conflict with the repeated field "int64_field".
+    optional int64 int64_field_count = 1001;
+    optional int64 int64_field_list = 1002;
+  }
+}
+

+ 50 - 0
java/src/test/java/com/google/protobuf/test_check_utf8.proto

@@ -0,0 +1,50 @@
+// 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: Jacob Butcher (jbaum@google.com)
+//
+// Test file option java_string_check_utf8.
+
+package proto2_test_check_utf8;
+
+option java_outer_classname = "TestCheckUtf8";
+option java_string_check_utf8 = true;
+
+message StringWrapper {
+  required string req = 1;
+  optional string opt = 2;
+  repeated string rep = 3;
+}
+
+message BytesWrapper {
+  required bytes req = 1;
+  optional bytes opt = 2;
+  repeated bytes rep = 3;
+}

+ 51 - 0
java/src/test/java/com/google/protobuf/test_check_utf8_size.proto

@@ -0,0 +1,51 @@
+// 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: Jacob Butcher (jbaum@google.com)
+//
+// Test file option java_string_check_utf8.
+
+package proto2_test_check_utf8_size;
+
+option java_outer_classname = "TestCheckUtf8Size";
+option java_string_check_utf8 = true;
+option optimize_for = CODE_SIZE;
+
+message StringWrapperSize {
+  required string req = 1;
+  optional string opt = 2;
+  repeated string rep = 3;
+}
+
+message BytesWrapperSize {
+  required bytes req = 1;
+  optional bytes opt = 2;
+  repeated bytes rep = 3;
+}

+ 43 - 0
java/src/test/java/com/google/protobuf/test_custom_options.proto

@@ -0,0 +1,43 @@
+// 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: Feng Xiao (xiaofeng@google.com)
+//
+// Test that custom options defined in a proto file's dependencies are properly
+// initialized.
+
+package protobuf_unittest;
+
+
+import "google/protobuf/unittest_custom_options.proto";
+
+message TestMessageWithCustomOptionsContainer {
+  optional TestMessageWithCustomOptions field = 1;
+}

+ 22 - 49
python/google/protobuf/pyext/python_descriptor.h → java/src/test/java/com/google/protobuf/test_extra_interfaces.proto

@@ -28,60 +28,33 @@
 // (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: petar@google.com (Petar Petrov)
+// Author: Darick Tong (darick@google.com)
 
-#ifndef GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
-#define GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
+package protobuf_unittest;
 
-#include <Python.h>
-#include <structmember.h>
+message Proto1 {
+  option experimental_java_message_interface =
+      "com.google.protobuf.ExtraInterfaces.HasBoolValue";
 
-#include <google/protobuf/descriptor.h>
+  option experimental_java_interface_extends =
+      "com.google.protobuf.ExtraInterfaces.HasByteValue";
 
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-#endif
+  option experimental_java_message_interface =
+      "com.google.protobuf.ExtraInterfaces.HasStringValue<Proto1>";
 
-namespace google {
-namespace protobuf {
-namespace python {
+  option experimental_java_builder_interface =
+      "com.google.protobuf.ExtraInterfaces.HasStringValueBuilder"
+      "<Proto1, Builder>";
 
-typedef struct {
-  PyObject_HEAD
+  optional string string_value = 1;
+  optional bool bool_value = 2;
+  optional bytes byte_value = 3;
+  optional int32 int_value = 4;
+}
 
-  // The proto2 descriptor that this object represents.
-  const google::protobuf::FieldDescriptor* descriptor;
+message Proto2 {
+  option experimental_java_message_interface =
+      "com.google.protobuf.ExtraInterfaces.HasBoolValue";
 
-  // Full name of the field (PyString).
-  PyObject* full_name;
-
-  // Name of the field (PyString).
-  PyObject* name;
-
-  // C++ type of the field (PyLong).
-  PyObject* cpp_type;
-
-  // Name of the field (PyLong).
-  PyObject* label;
-
-  // Identity of the descriptor (PyLong used as a poiner).
-  PyObject* id;
-} CFieldDescriptor;
-
-extern PyTypeObject CFieldDescriptor_Type;
-
-extern PyTypeObject CDescriptorPool_Type;
-
-
-PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args);
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* args);
-bool InitDescriptor();
-google::protobuf::DescriptorPool* GetDescriptorPool();
-
-}  // namespace python
-}  // namespace protobuf
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
+  optional bool bool_value = 1;
+}

+ 0 - 1717
python/google/protobuf/pyext/python-proto2.cc

@@ -1,1717 +0,0 @@
-// 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: petar@google.com (Petar Petrov)
-
-#include <Python.h>
-#include <map>
-#include <string>
-#include <vector>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/pyext/python_descriptor.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/message.h>
-#include <google/protobuf/unknown_field_set.h>
-#include <google/protobuf/pyext/python_protobuf.h>
-
-/* Is 64bit */
-#define IS_64BIT (SIZEOF_LONG == 8)
-
-#define FIELD_BELONGS_TO_MESSAGE(field_descriptor, message) \
-    ((message)->GetDescriptor() == (field_descriptor)->containing_type())
-
-#define FIELD_IS_REPEATED(field_descriptor)                 \
-    ((field_descriptor)->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED)
-
-#define GOOGLE_CHECK_GET_INT32(arg, value)                         \
-    int32 value;                                            \
-    if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \
-      return NULL;                                          \
-    }
-
-#define GOOGLE_CHECK_GET_INT64(arg, value)                         \
-    int64 value;                                            \
-    if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \
-      return NULL;                                          \
-    }
-
-#define GOOGLE_CHECK_GET_UINT32(arg, value)                        \
-    uint32 value;                                           \
-    if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \
-      return NULL;                                          \
-    }
-
-#define GOOGLE_CHECK_GET_UINT64(arg, value)                        \
-    uint64 value;                                           \
-    if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \
-      return NULL;                                          \
-    }
-
-#define GOOGLE_CHECK_GET_FLOAT(arg, value)                         \
-    float value;                                            \
-    if (!CheckAndGetFloat(arg, &value)) {                   \
-      return NULL;                                          \
-    }                                                       \
-
-#define GOOGLE_CHECK_GET_DOUBLE(arg, value)                        \
-    double value;                                           \
-    if (!CheckAndGetDouble(arg, &value)) {                  \
-      return NULL;                                          \
-    }
-
-#define GOOGLE_CHECK_GET_BOOL(arg, value)                          \
-    bool value;                                             \
-    if (!CheckAndGetBool(arg, &value)) {                    \
-      return NULL;                                          \
-    }
-
-#define C(str) const_cast<char*>(str)
-
-// --- Globals:
-
-// Constants used for integer type range checking.
-static PyObject* kPythonZero;
-static PyObject* kint32min_py;
-static PyObject* kint32max_py;
-static PyObject* kuint32max_py;
-static PyObject* kint64min_py;
-static PyObject* kint64max_py;
-static PyObject* kuint64max_py;
-
-namespace google {
-namespace protobuf {
-namespace python {
-
-// --- Support Routines:
-
-static void AddConstants(PyObject* module) {
-  struct NameValue {
-    char* name;
-    int32 value;
-  } constants[] = {
-    // Labels:
-    {"LABEL_OPTIONAL", google::protobuf::FieldDescriptor::LABEL_OPTIONAL},
-    {"LABEL_REQUIRED", google::protobuf::FieldDescriptor::LABEL_REQUIRED},
-    {"LABEL_REPEATED", google::protobuf::FieldDescriptor::LABEL_REPEATED},
-    // CPP types:
-    {"CPPTYPE_MESSAGE", google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE},
-    // Field Types:
-    {"TYPE_MESSAGE", google::protobuf::FieldDescriptor::TYPE_MESSAGE},
-    // End.
-    {NULL, 0}
-  };
-
-  for (NameValue* constant = constants;
-       constant->name != NULL; constant++) {
-    PyModule_AddIntConstant(module, constant->name, constant->value);
-  }
-}
-
-// --- CMessage Custom Type:
-
-// ------ Type Forward Declaration:
-
-struct CMessage;
-struct CMessage_Type;
-
-static void CMessageDealloc(CMessage* self);
-static int CMessageInit(CMessage* self, PyObject *args, PyObject *kwds);
-static PyObject* CMessageStr(CMessage* self);
-
-static PyObject* CMessage_AddMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_AddRepeatedScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_AssignRepeatedScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_ByteSize(CMessage* self, PyObject* args);
-static PyObject* CMessage_Clear(CMessage* self, PyObject* args);
-static PyObject* CMessage_ClearField(CMessage* self, PyObject* args);
-static PyObject* CMessage_ClearFieldByDescriptor(
-    CMessage* self, PyObject* args);
-static PyObject* CMessage_CopyFrom(CMessage* self, PyObject* args);
-static PyObject* CMessage_DebugString(CMessage* self, PyObject* args);
-static PyObject* CMessage_DeleteRepeatedField(CMessage* self, PyObject* args);
-static PyObject* CMessage_Equals(CMessage* self, PyObject* args);
-static PyObject* CMessage_FieldLength(CMessage* self, PyObject* args);
-static PyObject* CMessage_FindInitializationErrors(CMessage* self);
-static PyObject* CMessage_GetRepeatedMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_GetRepeatedScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_GetScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_HasField(CMessage* self, PyObject* args);
-static PyObject* CMessage_HasFieldByDescriptor(CMessage* self, PyObject* args);
-static PyObject* CMessage_IsInitialized(CMessage* self, PyObject* args);
-static PyObject* CMessage_ListFields(CMessage* self, PyObject* args);
-static PyObject* CMessage_MergeFrom(CMessage* self, PyObject* args);
-static PyObject* CMessage_MergeFromString(CMessage* self, PyObject* args);
-static PyObject* CMessage_MutableMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_NewSubMessage(CMessage* self, PyObject* args);
-static PyObject* CMessage_SetScalar(CMessage* self, PyObject* args);
-static PyObject* CMessage_SerializePartialToString(
-    CMessage* self, PyObject* args);
-static PyObject* CMessage_SerializeToString(CMessage* self, PyObject* args);
-static PyObject* CMessage_SetInParent(CMessage* self, PyObject* args);
-static PyObject* CMessage_SwapRepeatedFieldElements(
-    CMessage* self, PyObject* args);
-
-// ------ Object Definition:
-
-typedef struct CMessage {
-  PyObject_HEAD
-
-  struct CMessage* parent;  // NULL if wasn't created from another message.
-  CFieldDescriptor* parent_field;
-  const char* full_name;
-  google::protobuf::Message* message;
-  bool free_message;
-  bool read_only;
-} CMessage;
-
-// ------ Method Table:
-
-#define CMETHOD(name, args, doc)   \
-  { C(#name), (PyCFunction)CMessage_##name, args, C(doc) }
-static PyMethodDef CMessageMethods[] = {
-  CMETHOD(AddMessage, METH_O,
-          "Adds a new message to a repeated composite field."),
-  CMETHOD(AddRepeatedScalar, METH_VARARGS,
-          "Adds a scalar to a repeated scalar field."),
-  CMETHOD(AssignRepeatedScalar, METH_VARARGS,
-          "Clears and sets the values of a repeated scalar field."),
-  CMETHOD(ByteSize, METH_NOARGS,
-          "Returns the size of the message in bytes."),
-  CMETHOD(Clear, METH_O,
-          "Clears a protocol message."),
-  CMETHOD(ClearField, METH_VARARGS,
-          "Clears a protocol message field by name."),
-  CMETHOD(ClearFieldByDescriptor, METH_O,
-          "Clears a protocol message field by descriptor."),
-  CMETHOD(CopyFrom, METH_O,
-          "Copies a protocol message into the current message."),
-  CMETHOD(DebugString, METH_NOARGS,
-          "Returns the debug string of a protocol message."),
-  CMETHOD(DeleteRepeatedField, METH_VARARGS,
-          "Deletes a slice of values from a repeated field."),
-  CMETHOD(Equals, METH_O,
-          "Checks if two protocol messages are equal (by identity)."),
-  CMETHOD(FieldLength, METH_O,
-          "Returns the number of elements in a repeated field."),
-  CMETHOD(FindInitializationErrors, METH_NOARGS,
-          "Returns the initialization errors of a message."),
-  CMETHOD(GetRepeatedMessage, METH_VARARGS,
-          "Returns a message from a repeated composite field."),
-  CMETHOD(GetRepeatedScalar, METH_VARARGS,
-          "Returns a scalar value from a repeated scalar field."),
-  CMETHOD(GetScalar, METH_O,
-          "Returns the scalar value of a field."),
-  CMETHOD(HasField, METH_O,
-          "Checks if a message field is set."),
-  CMETHOD(HasFieldByDescriptor, METH_O,
-          "Checks if a message field is set by given its descriptor"),
-  CMETHOD(IsInitialized, METH_NOARGS,
-          "Checks if all required fields of a protocol message are set."),
-  CMETHOD(ListFields, METH_NOARGS,
-          "Lists all set fields of a message."),
-  CMETHOD(MergeFrom, METH_O,
-          "Merges a protocol message into the current message."),
-  CMETHOD(MergeFromString, METH_O,
-          "Merges a serialized message into the current message."),
-  CMETHOD(MutableMessage, METH_O,
-          "Returns a new instance of a nested protocol message."),
-  CMETHOD(NewSubMessage, METH_O,
-          "Creates and returns a python message given the descriptor of a "
-          "composite field of the current message."),
-  CMETHOD(SetScalar, METH_VARARGS,
-          "Sets the value of a singular scalar field."),
-  CMETHOD(SerializePartialToString, METH_VARARGS,
-          "Serializes the message to a string, even if it isn't initialized."),
-  CMETHOD(SerializeToString, METH_NOARGS,
-          "Serializes the message to a string, only for initialized messages."),
-  CMETHOD(SetInParent, METH_NOARGS,
-          "Sets the has bit of the given field in its parent message."),
-  CMETHOD(SwapRepeatedFieldElements, METH_VARARGS,
-          "Swaps the elements in two positions in a repeated field."),
-  { NULL, NULL }
-};
-#undef CMETHOD
-
-static PyMemberDef CMessageMembers[] = {
-  { C("full_name"), T_STRING, offsetof(CMessage, full_name), 0, "Full name" },
-  { NULL }
-};
-
-// ------ Type Definition:
-
-// The definition for the type object that captures the type of CMessage
-// in Python.
-PyTypeObject CMessage_Type = {
-  PyObject_HEAD_INIT(&PyType_Type)
-  0,
-  C("google.protobuf.internal."
-    "_net_proto2___python."
-    "CMessage"),                       // tp_name
-  sizeof(CMessage),                    //  tp_basicsize
-  0,                                   //  tp_itemsize
-  (destructor)CMessageDealloc,         //  tp_dealloc
-  0,                                   //  tp_print
-  0,                                   //  tp_getattr
-  0,                                   //  tp_setattr
-  0,                                   //  tp_compare
-  0,                                   //  tp_repr
-  0,                                   //  tp_as_number
-  0,                                   //  tp_as_sequence
-  0,                                   //  tp_as_mapping
-  0,                                   //  tp_hash
-  0,                                   //  tp_call
-  (reprfunc)CMessageStr,               //  tp_str
-  0,                                   //  tp_getattro
-  0,                                   //  tp_setattro
-  0,                                   //  tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  //  tp_flags
-  C("A ProtocolMessage"),              //  tp_doc
-  0,                                   //  tp_traverse
-  0,                                   //  tp_clear
-  0,                                   //  tp_richcompare
-  0,                                   //  tp_weaklistoffset
-  0,                                   //  tp_iter
-  0,                                   //  tp_iternext
-  CMessageMethods,                     //  tp_methods
-  CMessageMembers,                     //  tp_members
-  0,                                   //  tp_getset
-  0,                                   //  tp_base
-  0,                                   //  tp_dict
-  0,                                   //  tp_descr_get
-  0,                                   //  tp_descr_set
-  0,                                   //  tp_dictoffset
-  (initproc)CMessageInit,              //  tp_init
-  PyType_GenericAlloc,                 //  tp_alloc
-  PyType_GenericNew,                   //  tp_new
-  PyObject_Del,                        //  tp_free
-};
-
-// ------ Helper Functions:
-
-static void FormatTypeError(PyObject* arg, char* expected_types) {
-  PyObject* repr = PyObject_Repr(arg);
-  PyErr_Format(PyExc_TypeError,
-               "%.100s has type %.100s, but expected one of: %s",
-               PyString_AS_STRING(repr),
-               arg->ob_type->tp_name,
-               expected_types);
-  Py_DECREF(repr);
-}
-
-template <class T>
-static bool CheckAndGetInteger(
-    PyObject* arg, T* value, PyObject* min, PyObject* max) {
-  bool is_long = PyLong_Check(arg);
-  if (!PyInt_Check(arg) && !is_long) {
-    FormatTypeError(arg, "int, long");
-    return false;
-  }
-
-  if (PyObject_Compare(min, arg) > 0 || PyObject_Compare(max, arg) < 0) {
-    PyObject* s = PyObject_Str(arg);
-    PyErr_Format(PyExc_ValueError,
-                 "Value out of range: %s",
-                 PyString_AS_STRING(s));
-    Py_DECREF(s);
-    return false;
-  }
-  if (is_long) {
-    if (min == kPythonZero) {
-      *value = static_cast<T>(PyLong_AsUnsignedLongLong(arg));
-    } else {
-      *value = static_cast<T>(PyLong_AsLongLong(arg));
-    }
-  } else {
-    *value = static_cast<T>(PyInt_AsLong(arg));
-  }
-  return true;
-}
-
-static bool CheckAndGetDouble(PyObject* arg, double* value) {
-  if (!PyInt_Check(arg) && !PyLong_Check(arg) &&
-      !PyFloat_Check(arg)) {
-    FormatTypeError(arg, "int, long, float");
-    return false;
-  }
-  *value = PyFloat_AsDouble(arg);
-  return true;
-}
-
-static bool CheckAndGetFloat(PyObject* arg, float* value) {
-  double double_value;
-  if (!CheckAndGetDouble(arg, &double_value)) {
-    return false;
-  }
-  *value = static_cast<float>(double_value);
-  return true;
-}
-
-static bool CheckAndGetBool(PyObject* arg, bool* value) {
-  if (!PyInt_Check(arg) && !PyBool_Check(arg) && !PyLong_Check(arg)) {
-    FormatTypeError(arg, "int, long, bool");
-    return false;
-  }
-  *value = static_cast<bool>(PyInt_AsLong(arg));
-  return true;
-}
-
-google::protobuf::DynamicMessageFactory* global_message_factory = NULL;
-static const google::protobuf::Message* CreateMessage(const char* message_type) {
-  string message_name(message_type);
-  const google::protobuf::Descriptor* descriptor =
-      GetDescriptorPool()->FindMessageTypeByName(message_name);
-  if (descriptor == NULL) {
-    return NULL;
-  }
-  return global_message_factory->GetPrototype(descriptor);
-}
-
-static void ReleaseSubMessage(google::protobuf::Message* message,
-                           const google::protobuf::FieldDescriptor* field_descriptor,
-                           CMessage* child_cmessage) {
-  Message* released_message = message->GetReflection()->ReleaseMessage(
-      message, field_descriptor, global_message_factory);
-  GOOGLE_DCHECK(child_cmessage->message != NULL);
-  // ReleaseMessage will return NULL which differs from
-  // child_cmessage->message, if the field does not exist.  In this case,
-  // the latter points to the default instance via a const_cast<>, so we
-  // have to reset it to a new mutable object since we are taking ownership.
-  if (released_message == NULL) {
-    const Message* prototype = global_message_factory->GetPrototype(
-        child_cmessage->message->GetDescriptor());
-    GOOGLE_DCHECK(prototype != NULL);
-    child_cmessage->message = prototype->New();
-  }
-  child_cmessage->parent = NULL;
-  child_cmessage->parent_field = NULL;
-  child_cmessage->free_message = true;
-  child_cmessage->read_only = false;
-}
-
-static bool CheckAndSetString(
-    PyObject* arg, google::protobuf::Message* message,
-    const google::protobuf::FieldDescriptor* descriptor,
-    const google::protobuf::Reflection* reflection,
-    bool append,
-    int index) {
-  GOOGLE_DCHECK(descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
-         descriptor->type() == google::protobuf::FieldDescriptor::TYPE_BYTES);
-  if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
-    if (!PyString_Check(arg) && !PyUnicode_Check(arg)) {
-      FormatTypeError(arg, "str, unicode");
-      return false;
-    }
-
-    if (PyString_Check(arg)) {
-      PyObject* unicode = PyUnicode_FromEncodedObject(arg, "ascii", NULL);
-      if (unicode == NULL) {
-        PyObject* repr = PyObject_Repr(arg);
-        PyErr_Format(PyExc_ValueError,
-                     "%s has type str, but isn't in 7-bit ASCII "
-                     "encoding. Non-ASCII strings must be converted to "
-                     "unicode objects before being added.",
-                     PyString_AS_STRING(repr));
-        Py_DECREF(repr);
-        return false;
-      } else {
-        Py_DECREF(unicode);
-      }
-    }
-  } else if (!PyString_Check(arg)) {
-    FormatTypeError(arg, "str");
-    return false;
-  }
-
-  PyObject* encoded_string = NULL;
-  if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
-    if (PyString_Check(arg)) {
-      encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL);
-    } else {
-      encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL);
-    }
-  } else {
-    // In this case field type is "bytes".
-    encoded_string = arg;
-    Py_INCREF(encoded_string);
-  }
-
-  if (encoded_string == NULL) {
-    return false;
-  }
-
-  char* value;
-  Py_ssize_t value_len;
-  if (PyString_AsStringAndSize(encoded_string, &value, &value_len) < 0) {
-    Py_DECREF(encoded_string);
-    return false;
-  }
-
-  string value_string(value, value_len);
-  if (append) {
-    reflection->AddString(message, descriptor, value_string);
-  } else if (index < 0) {
-    reflection->SetString(message, descriptor, value_string);
-  } else {
-    reflection->SetRepeatedString(message, descriptor, index, value_string);
-  }
-  Py_DECREF(encoded_string);
-  return true;
-}
-
-static PyObject* ToStringObject(
-    const google::protobuf::FieldDescriptor* descriptor, string value) {
-  if (descriptor->type() != google::protobuf::FieldDescriptor::TYPE_STRING) {
-    return PyString_FromStringAndSize(value.c_str(), value.length());
-  }
-
-  PyObject* result = PyUnicode_DecodeUTF8(value.c_str(), value.length(), NULL);
-  // If the string can't be decoded in UTF-8, just return a string object that
-  // contains the raw bytes. This can't happen if the value was assigned using
-  // the members of the Python message object, but can happen if the values were
-  // parsed from the wire (binary).
-  if (result == NULL) {
-    PyErr_Clear();
-    result = PyString_FromStringAndSize(value.c_str(), value.length());
-  }
-  return result;
-}
-
-static void AssureWritable(CMessage* self) {
-  if (self == NULL ||
-      self->parent == NULL ||
-      self->parent_field == NULL) {
-    return;
-  }
-
-  if (!self->read_only) {
-    return;
-  }
-
-  AssureWritable(self->parent);
-
-  google::protobuf::Message* message = self->parent->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  self->message = reflection->MutableMessage(
-      message, self->parent_field->descriptor, global_message_factory);
-  self->read_only = false;
-}
-
-static PyObject* InternalGetScalar(
-    google::protobuf::Message* message,
-    const google::protobuf::FieldDescriptor* field_descriptor) {
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return NULL;
-  }
-
-  PyObject* result = NULL;
-  switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
-      int32 value = reflection->GetInt32(*message, field_descriptor);
-      result = PyInt_FromLong(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
-      int64 value = reflection->GetInt64(*message, field_descriptor);
-#if IS_64BIT
-      result = PyInt_FromLong(value);
-#else
-      result = PyLong_FromLongLong(value);
-#endif
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
-      uint32 value = reflection->GetUInt32(*message, field_descriptor);
-#if IS_64BIT
-      result = PyInt_FromLong(value);
-#else
-      result = PyLong_FromLongLong(value);
-#endif
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
-      uint64 value = reflection->GetUInt64(*message, field_descriptor);
-#if IS_64BIT
-      if (value <= static_cast<uint64>(kint64max)) {
-        result = PyInt_FromLong(static_cast<uint64>(value));
-      }
-#else
-      if (value <= static_cast<uint32>(kint32max)) {
-        result = PyInt_FromLong(static_cast<uint32>(value));
-      }
-#endif
-      else {  // NOLINT
-        result = PyLong_FromUnsignedLongLong(value);
-      }
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
-      float value = reflection->GetFloat(*message, field_descriptor);
-      result = PyFloat_FromDouble(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
-      double value = reflection->GetDouble(*message, field_descriptor);
-      result = PyFloat_FromDouble(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
-      bool value = reflection->GetBool(*message, field_descriptor);
-      result = PyBool_FromLong(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
-      string value = reflection->GetString(*message, field_descriptor);
-      result = ToStringObject(field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
-      if (!message->GetReflection()->HasField(*message, field_descriptor)) {
-        // Look for the value in the unknown fields.
-        google::protobuf::UnknownFieldSet* unknown_field_set =
-            message->GetReflection()->MutableUnknownFields(message);
-        for (int i = 0; i < unknown_field_set->field_count(); ++i) {
-          if (unknown_field_set->field(i).number() ==
-              field_descriptor->number()) {
-            result = PyInt_FromLong(unknown_field_set->field(i).varint());
-            break;
-          }
-        }
-      }
-
-      if (result == NULL) {
-        const google::protobuf::EnumValueDescriptor* enum_value =
-            message->GetReflection()->GetEnum(*message, field_descriptor);
-        result = PyInt_FromLong(enum_value->number());
-      }
-      break;
-    }
-    default:
-      PyErr_Format(
-          PyExc_SystemError, "Getting a value from a field of unknown type %d",
-          field_descriptor->cpp_type());
-  }
-
-  return result;
-}
-
-static PyObject* InternalSetScalar(
-    google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor,
-    PyObject* arg) {
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return NULL;
-  }
-
-  switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
-      GOOGLE_CHECK_GET_INT32(arg, value);
-      reflection->SetInt32(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
-      GOOGLE_CHECK_GET_INT64(arg, value);
-      reflection->SetInt64(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
-      GOOGLE_CHECK_GET_UINT32(arg, value);
-      reflection->SetUInt32(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
-      GOOGLE_CHECK_GET_UINT64(arg, value);
-      reflection->SetUInt64(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
-      GOOGLE_CHECK_GET_FLOAT(arg, value);
-      reflection->SetFloat(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
-      GOOGLE_CHECK_GET_DOUBLE(arg, value);
-      reflection->SetDouble(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
-      GOOGLE_CHECK_GET_BOOL(arg, value);
-      reflection->SetBool(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
-      if (!CheckAndSetString(
-          arg, message, field_descriptor, reflection, false, -1)) {
-        return NULL;
-      }
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
-      GOOGLE_CHECK_GET_INT32(arg, value);
-      const google::protobuf::EnumDescriptor* enum_descriptor =
-          field_descriptor->enum_type();
-      const google::protobuf::EnumValueDescriptor* enum_value =
-          enum_descriptor->FindValueByNumber(value);
-      if (enum_value != NULL) {
-        reflection->SetEnum(message, field_descriptor, enum_value);
-      } else {
-        bool added = false;
-        // Add the value to the unknown fields.
-        google::protobuf::UnknownFieldSet* unknown_field_set =
-            message->GetReflection()->MutableUnknownFields(message);
-        for (int i = 0; i < unknown_field_set->field_count(); ++i) {
-          if (unknown_field_set->field(i).number() ==
-              field_descriptor->number()) {
-            unknown_field_set->mutable_field(i)->set_varint(value);
-            added = true;
-            break;
-          }
-        }
-
-        if (!added) {
-          unknown_field_set->AddVarint(field_descriptor->number(), value);
-        }
-        reflection->ClearField(message, field_descriptor);
-      }
-      break;
-    }
-    default:
-      PyErr_Format(
-          PyExc_SystemError, "Setting value to a field of unknown type %d",
-          field_descriptor->cpp_type());
-  }
-
-  Py_RETURN_NONE;
-}
-
-static PyObject* InternalAddRepeatedScalar(
-    google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor,
-    PyObject* arg) {
-
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return NULL;
-  }
-
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
-      GOOGLE_CHECK_GET_INT32(arg, value);
-      reflection->AddInt32(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
-      GOOGLE_CHECK_GET_INT64(arg, value);
-      reflection->AddInt64(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
-      GOOGLE_CHECK_GET_UINT32(arg, value);
-      reflection->AddUInt32(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
-      GOOGLE_CHECK_GET_UINT64(arg, value);
-      reflection->AddUInt64(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
-      GOOGLE_CHECK_GET_FLOAT(arg, value);
-      reflection->AddFloat(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
-      GOOGLE_CHECK_GET_DOUBLE(arg, value);
-      reflection->AddDouble(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
-      GOOGLE_CHECK_GET_BOOL(arg, value);
-      reflection->AddBool(message, field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
-      if (!CheckAndSetString(
-          arg, message, field_descriptor, reflection, true, -1)) {
-        return NULL;
-      }
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
-      GOOGLE_CHECK_GET_INT32(arg, value);
-      const google::protobuf::EnumDescriptor* enum_descriptor =
-          field_descriptor->enum_type();
-      const google::protobuf::EnumValueDescriptor* enum_value =
-          enum_descriptor->FindValueByNumber(value);
-      if (enum_value != NULL) {
-        reflection->AddEnum(message, field_descriptor, enum_value);
-      } else {
-        PyObject* s = PyObject_Str(arg);
-        PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                     PyString_AS_STRING(s));
-        Py_DECREF(s);
-        return NULL;
-      }
-      break;
-    }
-    default:
-      PyErr_Format(
-          PyExc_SystemError, "Adding value to a field of unknown type %d",
-          field_descriptor->cpp_type());
-  }
-
-  Py_RETURN_NONE;
-}
-
-static PyObject* InternalGetRepeatedScalar(
-    CMessage* cmessage, const google::protobuf::FieldDescriptor* field_descriptor,
-    int index) {
-  google::protobuf::Message* message = cmessage->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-
-  int field_size = reflection->FieldSize(*message, field_descriptor);
-  if (index < 0) {
-    index = field_size + index;
-  }
-  if (index < 0 || index >= field_size) {
-    PyErr_Format(PyExc_IndexError,
-                 "list assignment index (%d) out of range", index);
-    return NULL;
-  }
-
-  PyObject* result = NULL;
-  switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
-      int32 value = reflection->GetRepeatedInt32(
-          *message, field_descriptor, index);
-      result = PyInt_FromLong(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
-      int64 value = reflection->GetRepeatedInt64(
-          *message, field_descriptor, index);
-      result = PyLong_FromLongLong(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
-      uint32 value = reflection->GetRepeatedUInt32(
-          *message, field_descriptor, index);
-      result = PyLong_FromLongLong(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
-      uint64 value = reflection->GetRepeatedUInt64(
-          *message, field_descriptor, index);
-      result = PyLong_FromUnsignedLongLong(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
-      float value = reflection->GetRepeatedFloat(
-          *message, field_descriptor, index);
-      result = PyFloat_FromDouble(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
-      double value = reflection->GetRepeatedDouble(
-          *message, field_descriptor, index);
-      result = PyFloat_FromDouble(value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
-      bool value = reflection->GetRepeatedBool(
-          *message, field_descriptor, index);
-      result = PyBool_FromLong(value ? 1 : 0);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
-      const google::protobuf::EnumValueDescriptor* enum_value =
-          message->GetReflection()->GetRepeatedEnum(
-              *message, field_descriptor, index);
-      result = PyInt_FromLong(enum_value->number());
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
-      string value = reflection->GetRepeatedString(
-          *message, field_descriptor, index);
-      result = ToStringObject(field_descriptor, value);
-      break;
-    }
-    case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
-      CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
-      if (py_cmsg == NULL) {
-        return NULL;
-      }
-      const google::protobuf::Message& msg = reflection->GetRepeatedMessage(
-          *message, field_descriptor, index);
-      py_cmsg->parent = cmessage;
-      py_cmsg->full_name = field_descriptor->full_name().c_str();
-      py_cmsg->message = const_cast<google::protobuf::Message*>(&msg);
-      py_cmsg->free_message = false;
-      py_cmsg->read_only = false;
-      result = reinterpret_cast<PyObject*>(py_cmsg);
-      break;
-    }
-    default:
-      PyErr_Format(
-          PyExc_SystemError,
-          "Getting value from a repeated field of unknown type %d",
-          field_descriptor->cpp_type());
-  }
-
-  return result;
-}
-
-static PyObject* InternalGetRepeatedScalarSlice(
-    CMessage* cmessage, const google::protobuf::FieldDescriptor* field_descriptor,
-    PyObject* slice) {
-  Py_ssize_t from;
-  Py_ssize_t to;
-  Py_ssize_t step;
-  Py_ssize_t length;
-  bool return_list = false;
-  google::protobuf::Message* message = cmessage->message;
-
-  if (PyInt_Check(slice)) {
-    from = to = PyInt_AsLong(slice);
-  } else if (PyLong_Check(slice)) {
-    from = to = PyLong_AsLong(slice);
-  } else if (PySlice_Check(slice)) {
-    const google::protobuf::Reflection* reflection = message->GetReflection();
-    length = reflection->FieldSize(*message, field_descriptor);
-    PySlice_GetIndices(
-        reinterpret_cast<PySliceObject*>(slice), length, &from, &to, &step);
-    return_list = true;
-  } else {
-    PyErr_SetString(PyExc_TypeError, "list indices must be integers");
-    return NULL;
-  }
-
-  if (!return_list) {
-    return InternalGetRepeatedScalar(cmessage, field_descriptor, from);
-  }
-
-  PyObject* list = PyList_New(0);
-  if (list == NULL) {
-    return NULL;
-  }
-
-  if (from <= to) {
-    if (step < 0) return list;
-    for (Py_ssize_t index = from; index < to; index += step) {
-      if (index < 0 || index >= length) break;
-      PyObject* s = InternalGetRepeatedScalar(
-          cmessage, field_descriptor, index);
-      PyList_Append(list, s);
-      Py_DECREF(s);
-    }
-  } else {
-    if (step > 0) return list;
-    for (Py_ssize_t index = from; index > to; index += step) {
-      if (index < 0 || index >= length) break;
-      PyObject* s = InternalGetRepeatedScalar(
-          cmessage, field_descriptor, index);
-      PyList_Append(list, s);
-      Py_DECREF(s);
-    }
-  }
-  return list;
-}
-
-// ------ C Constructor/Destructor:
-
-static int CMessageInit(CMessage* self, PyObject *args, PyObject *kwds) {
-  self->message = NULL;
-  return 0;
-}
-
-static void CMessageDealloc(CMessage* self) {
-  if (self->free_message) {
-    if (self->read_only) {
-      PyErr_WriteUnraisable(reinterpret_cast<PyObject*>(self));
-    }
-    delete self->message;
-  }
-  self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
-}
-
-// ------ Methods:
-
-static PyObject* CMessage_Clear(CMessage* self, PyObject* arg) {
-  AssureWritable(self);
-  google::protobuf::Message* message = self->message;
-
-  // This block of code is equivalent to the following:
-  // for cfield_descriptor, child_cmessage in arg:
-  //   ReleaseSubMessage(cfield_descriptor, child_cmessage)
-  if (!PyList_Check(arg)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a list");
-    return NULL;
-  }
-  PyObject* messages_to_clear = arg;
-  Py_ssize_t num_messages_to_clear = PyList_GET_SIZE(messages_to_clear);
-  for(int i = 0; i < num_messages_to_clear; ++i) {
-    PyObject* message_tuple = PyList_GET_ITEM(messages_to_clear, i);
-    if (!PyTuple_Check(message_tuple) || PyTuple_GET_SIZE(message_tuple) != 2) {
-      PyErr_SetString(PyExc_TypeError, "Must be a tuple of size 2");
-      return NULL;
-    }
-
-    PyObject* py_cfield_descriptor = PyTuple_GET_ITEM(message_tuple, 0);
-    PyObject* py_child_cmessage = PyTuple_GET_ITEM(message_tuple, 1);
-    if (!PyObject_TypeCheck(py_cfield_descriptor, &CFieldDescriptor_Type) ||
-        !PyObject_TypeCheck(py_child_cmessage, &CMessage_Type)) {
-      PyErr_SetString(PyExc_ValueError, "Invalid Tuple");
-      return NULL;
-    }
-
-    CFieldDescriptor* cfield_descriptor = reinterpret_cast<CFieldDescriptor *>(
-        py_cfield_descriptor);
-    CMessage* child_cmessage = reinterpret_cast<CMessage *>(py_child_cmessage);
-    ReleaseSubMessage(message, cfield_descriptor->descriptor, child_cmessage);
-  }
-
-  message->Clear();
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_IsInitialized(CMessage* self, PyObject* args) {
-  return PyBool_FromLong(self->message->IsInitialized() ? 1 : 0);
-}
-
-static PyObject* CMessage_HasField(CMessage* self, PyObject* arg) {
-  char* field_name;
-  if (PyString_AsStringAndSize(arg, &field_name, NULL) < 0) {
-    return NULL;
-  }
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      descriptor->FindFieldByName(field_name);
-  if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
-    return NULL;
-  }
-
-  bool has_field =
-      message->GetReflection()->HasField(*message, field_descriptor);
-  return PyBool_FromLong(has_field ? 1 : 0);
-}
-
-static PyObject* CMessage_HasFieldByDescriptor(CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cfield_descriptor = NULL;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      cfield_descriptor->descriptor;
-
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(PyExc_KeyError,
-                    "Field does not belong to message!");
-    return NULL;
-  }
-
-  if (FIELD_IS_REPEATED(field_descriptor)) {
-    PyErr_SetString(PyExc_KeyError,
-                    "Field is repeated. A singular method is required.");
-    return NULL;
-  }
-
-  bool has_field =
-      message->GetReflection()->HasField(*message, field_descriptor);
-  return PyBool_FromLong(has_field ? 1 : 0);
-}
-
-static PyObject* CMessage_ClearFieldByDescriptor(
-    CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cfield_descriptor = NULL;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      cfield_descriptor->descriptor;
-
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(PyExc_KeyError,
-                    "Field does not belong to message!");
-    return NULL;
-  }
-
-  message->GetReflection()->ClearField(message, field_descriptor);
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_ClearField(CMessage* self, PyObject* args) {
-  char* field_name;
-  CMessage* child_cmessage = NULL;
-  if (!PyArg_ParseTuple(args, C("s|O!:ClearField"), &field_name,
-                        &CMessage_Type, &child_cmessage)) {
-    return NULL;
-  }
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      descriptor->FindFieldByName(field_name);
-  if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
-    return NULL;
-  }
-
-  if (child_cmessage != NULL && !FIELD_IS_REPEATED(field_descriptor)) {
-    ReleaseSubMessage(message, field_descriptor, child_cmessage);
-  } else {
-    message->GetReflection()->ClearField(message, field_descriptor);
-  }
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_GetScalar(CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cdescriptor = NULL;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cdescriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
-  google::protobuf::Message* message = self->message;
-  return InternalGetScalar(message, cdescriptor->descriptor);
-}
-
-static PyObject* CMessage_GetRepeatedScalar(CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  PyObject* slice;
-  if (!PyArg_ParseTuple(args, C("O!O:GetRepeatedScalar"),
-                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
-    return NULL;
-  }
-
-  return InternalGetRepeatedScalarSlice(
-      self, cfield_descriptor->descriptor, slice);
-}
-
-static PyObject* CMessage_AssignRepeatedScalar(CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  PyObject* slice;
-  if (!PyArg_ParseTuple(args, C("O!O:AssignRepeatedScalar"),
-                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
-    return NULL;
-  }
-
-  AssureWritable(self);
-  google::protobuf::Message* message = self->message;
-  message->GetReflection()->ClearField(message, cfield_descriptor->descriptor);
-
-  PyObject* iter = PyObject_GetIter(slice);
-  PyObject* next;
-  while ((next = PyIter_Next(iter)) != NULL) {
-    if (InternalAddRepeatedScalar(
-            message, cfield_descriptor->descriptor, next) == NULL) {
-      Py_DECREF(next);
-      Py_DECREF(iter);
-      return NULL;
-    }
-    Py_DECREF(next);
-  }
-  Py_DECREF(iter);
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_DeleteRepeatedField(CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  PyObject* slice;
-  if (!PyArg_ParseTuple(args, C("O!O:DeleteRepeatedField"),
-                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
-    return NULL;
-  }
-  AssureWritable(self);
-
-  Py_ssize_t length, from, to, step, slice_length;
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      cfield_descriptor->descriptor;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  int min, max;
-  length = reflection->FieldSize(*message, field_descriptor);
-
-  if (PyInt_Check(slice) || PyLong_Check(slice)) {
-    from = to = PyLong_AsLong(slice);
-    if (from < 0) {
-      from = to = length + from;
-    }
-    step = 1;
-    min = max = from;
-
-    // Range check.
-    if (from < 0 || from >= length) {
-      PyErr_Format(PyExc_IndexError, "list assignment index out of range");
-      return NULL;
-    }
-  } else if (PySlice_Check(slice)) {
-    from = to = step = slice_length = 0;
-    PySlice_GetIndicesEx(
-        reinterpret_cast<PySliceObject*>(slice),
-        length, &from, &to, &step, &slice_length);
-    if (from < to) {
-      min = from;
-      max = to - 1;
-    } else {
-      min = to + 1;
-      max = from;
-    }
-  } else {
-    PyErr_SetString(PyExc_TypeError, "list indices must be integers");
-    return NULL;
-  }
-
-  Py_ssize_t i = from;
-  std::vector<bool> to_delete(length, false);
-  while (i >= min && i <= max) {
-    to_delete[i] = true;
-    i += step;
-  }
-
-  to = 0;
-  for (i = 0; i < length; ++i) {
-    if (!to_delete[i]) {
-      if (i != to) {
-        reflection->SwapElements(message, field_descriptor, i, to);
-      }
-      ++to;
-    }
-  }
-
-  while (i > to) {
-    reflection->RemoveLast(message, field_descriptor);
-    --i;
-  }
-
-  Py_RETURN_NONE;
-}
-
-
-static PyObject* CMessage_SetScalar(CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  PyObject* arg;
-  if (!PyArg_ParseTuple(args, C("O!O:SetScalar"),
-                        &CFieldDescriptor_Type, &cfield_descriptor, &arg)) {
-    return NULL;
-  }
-  AssureWritable(self);
-
-  return InternalSetScalar(self->message, cfield_descriptor->descriptor, arg);
-}
-
-static PyObject* CMessage_AddRepeatedScalar(CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  PyObject* value;
-  if (!PyArg_ParseTuple(args, C("O!O:AddRepeatedScalar"),
-                        &CFieldDescriptor_Type, &cfield_descriptor, &value)) {
-    return NULL;
-  }
-  AssureWritable(self);
-
-  return InternalAddRepeatedScalar(
-      self->message, cfield_descriptor->descriptor, value);
-}
-
-static PyObject* CMessage_FieldLength(CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cfield_descriptor;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
-  google::protobuf::Message* message = self->message;
-  int length = message->GetReflection()->FieldSize(
-      *message, cfield_descriptor->descriptor);
-  return PyInt_FromLong(length);
-}
-
-static PyObject* CMessage_DebugString(CMessage* self, PyObject* args) {
-  return PyString_FromString(self->message->DebugString().c_str());
-}
-
-static PyObject* CMessage_SerializeToString(CMessage* self, PyObject* args) {
-  int size = self->message->ByteSize();
-  if (size <= 0) {
-    return PyString_FromString("");
-  }
-  PyObject* result = PyString_FromStringAndSize(NULL, size);
-  if (result == NULL) {
-    return NULL;
-  }
-  char* buffer = PyString_AS_STRING(result);
-  self->message->SerializeWithCachedSizesToArray(
-      reinterpret_cast<uint8*>(buffer));
-  return result;
-}
-
-static PyObject* CMessage_SerializePartialToString(
-    CMessage* self, PyObject* args) {
-  string contents;
-  self->message->SerializePartialToString(&contents);
-  return PyString_FromStringAndSize(contents.c_str(), contents.size());
-}
-
-static PyObject* CMessageStr(CMessage* self) {
-  char str[1024];
-  str[sizeof(str) - 1] = 0;
-  snprintf(str, sizeof(str) - 1, "CMessage: <%p>", self->message);
-  return PyString_FromString(str);
-}
-
-static PyObject* CMessage_MergeFrom(CMessage* self, PyObject* arg) {
-  CMessage* other_message;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a message");
-    return NULL;
-  }
-
-  other_message = reinterpret_cast<CMessage*>(arg);
-  if (other_message->message->GetDescriptor() !=
-      self->message->GetDescriptor()) {
-    PyErr_Format(PyExc_TypeError,
-                 "Tried to merge from a message with a different type. "
-                 "to: %s, from: %s",
-                 self->message->GetDescriptor()->full_name().c_str(),
-                 other_message->message->GetDescriptor()->full_name().c_str());
-    return NULL;
-  }
-  AssureWritable(self);
-
-  self->message->MergeFrom(*other_message->message);
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_CopyFrom(CMessage* self, PyObject* arg) {
-  CMessage* other_message;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a message");
-    return NULL;
-  }
-
-  other_message = reinterpret_cast<CMessage*>(arg);
-  if (other_message->message->GetDescriptor() !=
-      self->message->GetDescriptor()) {
-    PyErr_Format(PyExc_TypeError,
-                 "Tried to copy from a message with a different type. "
-                 "to: %s, from: %s",
-                 self->message->GetDescriptor()->full_name().c_str(),
-                 other_message->message->GetDescriptor()->full_name().c_str());
-    return NULL;
-  }
-
-  AssureWritable(self);
-
-  self->message->CopyFrom(*other_message->message);
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_MergeFromString(CMessage* self, PyObject* arg) {
-  const void* data;
-  Py_ssize_t data_length;
-  if (PyObject_AsReadBuffer(arg, &data, &data_length) < 0) {
-    return NULL;
-  }
-
-  AssureWritable(self);
-  google::protobuf::io::CodedInputStream input(
-      reinterpret_cast<const uint8*>(data), data_length);
-  input.SetExtensionRegistry(GetDescriptorPool(), global_message_factory);
-  bool success = self->message->MergePartialFromCodedStream(&input);
-  if (success) {
-    return PyInt_FromLong(self->message->ByteSize());
-  } else {
-    return PyInt_FromLong(-1);
-  }
-}
-
-static PyObject* CMessage_ByteSize(CMessage* self, PyObject* args) {
-  return PyLong_FromLong(self->message->ByteSize());
-}
-
-static PyObject* CMessage_SetInParent(CMessage* self, PyObject* args) {
-  AssureWritable(self);
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_SwapRepeatedFieldElements(
-    CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  int index1, index2;
-  if (!PyArg_ParseTuple(args, C("O!ii:SwapRepeatedFieldElements"),
-                        &CFieldDescriptor_Type, &cfield_descriptor,
-                        &index1, &index2)) {
-    return NULL;
-  }
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-
-  reflection->SwapElements(
-      message, cfield_descriptor->descriptor, index1, index2);
-  Py_RETURN_NONE;
-}
-
-static PyObject* CMessage_AddMessage(CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cfield_descriptor;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-  AssureWritable(self);
-
-  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
-  if (py_cmsg == NULL) {
-    return NULL;
-  }
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  google::protobuf::Message* sub_message =
-      reflection->AddMessage(message, cfield_descriptor->descriptor);
-
-  py_cmsg->parent = NULL;
-  py_cmsg->full_name = sub_message->GetDescriptor()->full_name().c_str();
-  py_cmsg->message = sub_message;
-  py_cmsg->free_message = false;
-  py_cmsg->read_only = false;
-  return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-static PyObject* CMessage_GetRepeatedMessage(CMessage* self, PyObject* args) {
-  CFieldDescriptor* cfield_descriptor;
-  PyObject* slice;
-  if (!PyArg_ParseTuple(args, C("O!O:GetRepeatedMessage"),
-                        &CFieldDescriptor_Type, &cfield_descriptor, &slice)) {
-    return NULL;
-  }
-
-  return InternalGetRepeatedScalarSlice(
-      self, cfield_descriptor->descriptor, slice);
-}
-
-static PyObject* CMessage_NewSubMessage(CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cfield_descriptor;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-
-  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
-  if (py_cmsg == NULL) {
-    return NULL;
-  }
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  const google::protobuf::Message& sub_message =
-      reflection->GetMessage(*message, cfield_descriptor->descriptor,
-                             global_message_factory);
-
-  py_cmsg->full_name = sub_message.GetDescriptor()->full_name().c_str();
-  py_cmsg->parent = self;
-  py_cmsg->parent_field = cfield_descriptor;
-  py_cmsg->message = const_cast<google::protobuf::Message*>(&sub_message);
-  py_cmsg->free_message = false;
-  py_cmsg->read_only = true;
-  return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-static PyObject* CMessage_MutableMessage(CMessage* self, PyObject* arg) {
-  CFieldDescriptor* cfield_descriptor;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg),
-                          &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a field descriptor");
-    return NULL;
-  }
-  cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(arg);
-  AssureWritable(self);
-
-  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
-  if (py_cmsg == NULL) {
-    return NULL;
-  }
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  google::protobuf::Message* mutable_message =
-      reflection->MutableMessage(message, cfield_descriptor->descriptor,
-                                 global_message_factory);
-
-  py_cmsg->full_name = mutable_message->GetDescriptor()->full_name().c_str();
-  py_cmsg->message = mutable_message;
-  py_cmsg->free_message = false;
-  py_cmsg->read_only = false;
-  return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-static PyObject* CMessage_Equals(CMessage* self, PyObject* arg) {
-  CMessage* other_message;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a message");
-    return NULL;
-  }
-  other_message = reinterpret_cast<CMessage*>(arg);
-
-  if (other_message->message == self->message) {
-    return PyBool_FromLong(1);
-  }
-
-  if (other_message->message->GetDescriptor() !=
-      self->message->GetDescriptor()) {
-    return PyBool_FromLong(0);
-  }
-
-  return PyBool_FromLong(1);
-}
-
-static PyObject* CMessage_ListFields(CMessage* self, PyObject* args) {
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  vector<const google::protobuf::FieldDescriptor*> fields;
-  reflection->ListFields(*message, &fields);
-
-  PyObject* list = PyList_New(fields.size());
-  if (list == NULL) {
-    return NULL;
-  }
-
-  for (unsigned int i = 0; i < fields.size(); ++i) {
-    bool is_extension = fields[i]->is_extension();
-    PyObject* t = PyTuple_New(2);
-    if (t == NULL) {
-      Py_DECREF(list);
-      return NULL;
-    }
-
-    PyObject* is_extension_object = PyBool_FromLong(is_extension ? 1 : 0);
-
-    PyObject* field_name;
-    const string* s;
-    if (is_extension) {
-      s = &fields[i]->full_name();
-    } else {
-      s = &fields[i]->name();
-    }
-    field_name = PyString_FromStringAndSize(s->c_str(), s->length());
-    if (field_name == NULL) {
-      Py_DECREF(list);
-      Py_DECREF(t);
-      return NULL;
-    }
-
-    PyTuple_SET_ITEM(t, 0, is_extension_object);
-    PyTuple_SET_ITEM(t, 1, field_name);
-    PyList_SET_ITEM(list, i, t);
-  }
-
-  return list;
-}
-
-static PyObject* CMessage_FindInitializationErrors(CMessage* self) {
-  google::protobuf::Message* message = self->message;
-  vector<string> errors;
-  message->FindInitializationErrors(&errors);
-
-  PyObject* error_list = PyList_New(errors.size());
-  if (error_list == NULL) {
-    return NULL;
-  }
-  for (unsigned int i = 0; i < errors.size(); ++i) {
-    const string& error = errors[i];
-    PyObject* error_string = PyString_FromStringAndSize(
-        error.c_str(), error.length());
-    if (error_string == NULL) {
-      Py_DECREF(error_list);
-      return NULL;
-    }
-    PyList_SET_ITEM(error_list, i, error_string);
-  }
-  return error_list;
-}
-
-// ------ Python Constructor:
-
-PyObject* Python_NewCMessage(PyObject* ignored, PyObject* arg) {
-  const char* message_type = PyString_AsString(arg);
-  if (message_type == NULL) {
-    return NULL;
-  }
-
-  const google::protobuf::Message* message = CreateMessage(message_type);
-  if (message == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't create message of type %s!",
-                 message_type);
-    return NULL;
-  }
-
-  CMessage* py_cmsg = PyObject_New(CMessage, &CMessage_Type);
-  if (py_cmsg == NULL) {
-    return NULL;
-  }
-  py_cmsg->message = message->New();
-  py_cmsg->free_message = true;
-  py_cmsg->full_name = message->GetDescriptor()->full_name().c_str();
-  py_cmsg->read_only = false;
-  py_cmsg->parent = NULL;
-  py_cmsg->parent_field = NULL;
-  return reinterpret_cast<PyObject*>(py_cmsg);
-}
-
-// --- Module Functions (exposed to Python):
-
-PyMethodDef methods[] = {
-  { C("NewCMessage"), (PyCFunction)Python_NewCMessage,
-    METH_O,
-    C("Creates a new C++ protocol message, given its full name.") },
-  { C("NewCDescriptorPool"), (PyCFunction)Python_NewCDescriptorPool,
-    METH_NOARGS,
-    C("Creates a new C++ descriptor pool.") },
-  { C("BuildFile"), (PyCFunction)Python_BuildFile,
-    METH_O,
-    C("Registers a new protocol buffer file in the global C++ descriptor "
-      "pool.") },
-  {NULL}
-};
-
-// --- Exposing the C proto living inside Python proto to C code:
-
-extern const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
-extern Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);
-
-static const google::protobuf::Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
-  PyObject* c_msg_obj = PyObject_GetAttrString(msg, "_cmsg");
-  if (c_msg_obj == NULL) {
-    PyErr_Clear();
-    return NULL;
-  }
-  Py_DECREF(c_msg_obj);
-  if (!PyObject_TypeCheck(c_msg_obj, &CMessage_Type)) {
-    return NULL;
-  }
-  CMessage* c_msg = reinterpret_cast<CMessage*>(c_msg_obj);
-  return c_msg->message;
-}
-
-static google::protobuf::Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
-  PyObject* c_msg_obj = PyObject_GetAttrString(msg, "_cmsg");
-  if (c_msg_obj == NULL) {
-    PyErr_Clear();
-    return NULL;
-  }
-  Py_DECREF(c_msg_obj);
-  if (!PyObject_TypeCheck(c_msg_obj, &CMessage_Type)) {
-    return NULL;
-  }
-  CMessage* c_msg = reinterpret_cast<CMessage*>(c_msg_obj);
-  AssureWritable(c_msg);
-  return c_msg->message;
-}
-
-// --- Module Init Function:
-
-static const char module_docstring[] =
-"python-proto2 is a module that can be used to enhance proto2 Python API\n"
-"performance.\n"
-"\n"
-"It provides access to the protocol buffers C++ reflection API that\n"
-"implements the basic protocol buffer functions.";
-
-extern "C" {
-  void init_net_proto2___python() {
-    // Initialize constants.
-    kPythonZero = PyInt_FromLong(0);
-    kint32min_py = PyInt_FromLong(kint32min);
-    kint32max_py = PyInt_FromLong(kint32max);
-    kuint32max_py = PyLong_FromLongLong(kuint32max);
-    kint64min_py = PyLong_FromLongLong(kint64min);
-    kint64max_py = PyLong_FromLongLong(kint64max);
-    kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max);
-
-    global_message_factory = new DynamicMessageFactory(GetDescriptorPool());
-    global_message_factory->SetDelegateToGeneratedFactory(true);
-
-    // Export our functions to Python.
-    PyObject *m;
-    m = Py_InitModule3(C("_net_proto2___python"), methods, C(module_docstring));
-    if (m == NULL) {
-      return;
-    }
-
-    AddConstants(m);
-
-    CMessage_Type.tp_new = PyType_GenericNew;
-    if (PyType_Ready(&CMessage_Type) < 0) {
-      return;
-    }
-
-    if (!InitDescriptor()) {
-      return;
-    }
-
-    // Override {Get,Mutable}CProtoInsidePyProto.
-    GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl;
-    MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl;
-  }
-}
-
-}  // namespace python
-}  // namespace protobuf
-}  // namespace google

+ 0 - 337
python/google/protobuf/pyext/python_descriptor.cc

@@ -1,337 +0,0 @@
-// 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: petar@google.com (Petar Petrov)
-
-#include <Python.h>
-#include <string>
-
-#include <google/protobuf/pyext/python_descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-
-#define C(str) const_cast<char*>(str)
-
-namespace google {
-namespace protobuf {
-namespace python {
-
-
-static void CFieldDescriptorDealloc(CFieldDescriptor* self);
-
-static google::protobuf::DescriptorPool* g_descriptor_pool = NULL;
-
-static PyObject* CFieldDescriptor_GetFullName(
-    CFieldDescriptor* self, void *closure) {
-  Py_XINCREF(self->full_name);
-  return self->full_name;
-}
-
-static PyObject* CFieldDescriptor_GetName(
-    CFieldDescriptor *self, void *closure) {
-  Py_XINCREF(self->name);
-  return self->name;
-}
-
-static PyObject* CFieldDescriptor_GetCppType(
-    CFieldDescriptor *self, void *closure) {
-  Py_XINCREF(self->cpp_type);
-  return self->cpp_type;
-}
-
-static PyObject* CFieldDescriptor_GetLabel(
-    CFieldDescriptor *self, void *closure) {
-  Py_XINCREF(self->label);
-  return self->label;
-}
-
-static PyObject* CFieldDescriptor_GetID(
-    CFieldDescriptor *self, void *closure) {
-  Py_XINCREF(self->id);
-  return self->id;
-}
-
-
-static PyGetSetDef CFieldDescriptorGetters[] = {
-  { C("full_name"),
-    (getter)CFieldDescriptor_GetFullName, NULL, "Full name", NULL},
-  { C("name"),
-    (getter)CFieldDescriptor_GetName, NULL, "last name", NULL},
-  { C("cpp_type"),
-    (getter)CFieldDescriptor_GetCppType, NULL, "C++ Type", NULL},
-  { C("label"),
-    (getter)CFieldDescriptor_GetLabel, NULL, "Label", NULL},
-  { C("id"),
-    (getter)CFieldDescriptor_GetID, NULL, "ID", NULL},
-  {NULL}
-};
-
-PyTypeObject CFieldDescriptor_Type = {
-  PyObject_HEAD_INIT(&PyType_Type)
-  0,
-  C("google.protobuf.internal."
-    "_net_proto2___python."
-    "CFieldDescriptor"),                // tp_name
-  sizeof(CFieldDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  (destructor)CFieldDescriptorDealloc,  // tp_dealloc
-  0,                                    // tp_print
-  0,                                    // tp_getattr
-  0,                                    // tp_setattr
-  0,                                    // tp_compare
-  0,                                    // tp_repr
-  0,                                    // tp_as_number
-  0,                                    // tp_as_sequence
-  0,                                    // tp_as_mapping
-  0,                                    // tp_hash
-  0,                                    // tp_call
-  0,                                    // tp_str
-  0,                                    // tp_getattro
-  0,                                    // tp_setattro
-  0,                                    // tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Field Descriptor"),              // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  0,                                    // tp_methods
-  0,                                    // tp_members
-  CFieldDescriptorGetters,              // tp_getset
-  0,                                    // tp_base
-  0,                                    // tp_dict
-  0,                                    // tp_descr_get
-  0,                                    // tp_descr_set
-  0,                                    // tp_dictoffset
-  0,                                    // tp_init
-  PyType_GenericAlloc,                  // tp_alloc
-  PyType_GenericNew,                    // tp_new
-  PyObject_Del,                         // tp_free
-};
-
-static void CFieldDescriptorDealloc(CFieldDescriptor* self) {
-  Py_DECREF(self->full_name);
-  Py_DECREF(self->name);
-  Py_DECREF(self->cpp_type);
-  Py_DECREF(self->label);
-  Py_DECREF(self->id);
-  self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
-}
-
-typedef struct {
-  PyObject_HEAD
-
-  const google::protobuf::DescriptorPool* pool;
-} CDescriptorPool;
-
-static void CDescriptorPoolDealloc(CDescriptorPool* self);
-
-static PyObject* CDescriptorPool_NewCDescriptor(
-    const google::protobuf::FieldDescriptor* field_descriptor) {
-  CFieldDescriptor* cfield_descriptor = PyObject_New(
-      CFieldDescriptor, &CFieldDescriptor_Type);
-  if (cfield_descriptor == NULL) {
-    return NULL;
-  }
-  cfield_descriptor->descriptor = field_descriptor;
-
-  cfield_descriptor->full_name = PyString_FromString(
-      field_descriptor->full_name().c_str());
-  cfield_descriptor->name = PyString_FromString(
-      field_descriptor->name().c_str());
-  cfield_descriptor->cpp_type = PyLong_FromLong(field_descriptor->cpp_type());
-  cfield_descriptor->label = PyLong_FromLong(field_descriptor->label());
-  cfield_descriptor->id = PyLong_FromVoidPtr(cfield_descriptor);
-  return reinterpret_cast<PyObject*>(cfield_descriptor);
-}
-
-static PyObject* CDescriptorPool_FindFieldByName(
-    CDescriptorPool* self, PyObject* arg) {
-  const char* full_field_name = PyString_AsString(arg);
-  if (full_field_name == NULL) {
-    return NULL;
-  }
-
-  const google::protobuf::FieldDescriptor* field_descriptor = NULL;
-
-  field_descriptor = self->pool->FindFieldByName(full_field_name);
-
-
-  if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
-                 full_field_name);
-    return NULL;
-  }
-
-  return CDescriptorPool_NewCDescriptor(field_descriptor);
-}
-
-static PyObject* CDescriptorPool_FindExtensionByName(
-    CDescriptorPool* self, PyObject* arg) {
-  const char* full_field_name = PyString_AsString(arg);
-  if (full_field_name == NULL) {
-    return NULL;
-  }
-
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      self->pool->FindExtensionByName(full_field_name);
-  if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
-                 full_field_name);
-    return NULL;
-  }
-
-  return CDescriptorPool_NewCDescriptor(field_descriptor);
-}
-
-static PyMethodDef CDescriptorPoolMethods[] = {
-  { C("FindFieldByName"),
-    (PyCFunction)CDescriptorPool_FindFieldByName,
-    METH_O,
-    C("Searches for a field descriptor by full name.") },
-  { C("FindExtensionByName"),
-    (PyCFunction)CDescriptorPool_FindExtensionByName,
-    METH_O,
-    C("Searches for extension descriptor by full name.") },
-  {NULL}
-};
-
-PyTypeObject CDescriptorPool_Type = {
-  PyObject_HEAD_INIT(&PyType_Type)
-  0,
-  C("google.protobuf.internal."
-    "_net_proto2___python."
-    "CFieldDescriptor"),               // tp_name
-  sizeof(CDescriptorPool),             // tp_basicsize
-  0,                                   // tp_itemsize
-  (destructor)CDescriptorPoolDealloc,  // tp_dealloc
-  0,                                   // tp_print
-  0,                                   // tp_getattr
-  0,                                   // tp_setattr
-  0,                                   // tp_compare
-  0,                                   // tp_repr
-  0,                                   // tp_as_number
-  0,                                   // tp_as_sequence
-  0,                                   // tp_as_mapping
-  0,                                   // tp_hash
-  0,                                   // tp_call
-  0,                                   // tp_str
-  0,                                   // tp_getattro
-  0,                                   // tp_setattro
-  0,                                   // tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  // tp_flags
-  C("A Descriptor Pool"),              // tp_doc
-  0,                                   // tp_traverse
-  0,                                   // tp_clear
-  0,                                   // tp_richcompare
-  0,                                   // tp_weaklistoffset
-  0,                                   // tp_iter
-  0,                                   // tp_iternext
-  CDescriptorPoolMethods,              // tp_methods
-  0,                                   // tp_members
-  0,                                   // tp_getset
-  0,                                   // tp_base
-  0,                                   // tp_dict
-  0,                                   // tp_descr_get
-  0,                                   // tp_descr_set
-  0,                                   // tp_dictoffset
-  0,                                   // tp_init
-  PyType_GenericAlloc,                 // tp_alloc
-  PyType_GenericNew,                   // tp_new
-  PyObject_Del,                        // tp_free
-};
-
-static void CDescriptorPoolDealloc(CDescriptorPool* self) {
-  self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
-}
-
-google::protobuf::DescriptorPool* GetDescriptorPool() {
-  if (g_descriptor_pool == NULL) {
-    g_descriptor_pool = new google::protobuf::DescriptorPool(
-        google::protobuf::DescriptorPool::generated_pool());
-  }
-  return g_descriptor_pool;
-}
-
-PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args) {
-  CDescriptorPool* cdescriptor_pool = PyObject_New(
-      CDescriptorPool, &CDescriptorPool_Type);
-  if (cdescriptor_pool == NULL) {
-    return NULL;
-  }
-  cdescriptor_pool->pool = GetDescriptorPool();
-  return reinterpret_cast<PyObject*>(cdescriptor_pool);
-}
-
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) {
-  char* message_type;
-  Py_ssize_t message_len;
-
-  if (PyString_AsStringAndSize(arg, &message_type, &message_len) < 0) {
-    return NULL;
-  }
-
-  google::protobuf::FileDescriptorProto file_proto;
-  if (!file_proto.ParseFromArray(message_type, message_len)) {
-    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
-    return NULL;
-  }
-
-  if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
-      file_proto.name()) != NULL) {
-    Py_RETURN_NONE;
-  }
-
-  const google::protobuf::FileDescriptor* descriptor = GetDescriptorPool()->BuildFile(
-      file_proto);
-  if (descriptor == NULL) {
-    PyErr_SetString(PyExc_TypeError,
-                    "Couldn't build proto file into descriptor pool!");
-    return NULL;
-  }
-
-  Py_RETURN_NONE;
-}
-
-bool InitDescriptor() {
-  CFieldDescriptor_Type.tp_new = PyType_GenericNew;
-  if (PyType_Ready(&CFieldDescriptor_Type) < 0)
-    return false;
-
-  CDescriptorPool_Type.tp_new = PyType_GenericNew;
-  if (PyType_Ready(&CDescriptorPool_Type) < 0)
-    return false;
-  return true;
-}
-
-}  // namespace python
-}  // namespace protobuf
-}  // namespace google

+ 37 - 1
python/setup.py

@@ -72,7 +72,11 @@ def GenerateUnittestProtos():
   generate_proto("../src/google/protobuf/unittest_import_public.proto")
   generate_proto("../src/google/protobuf/unittest_mset.proto")
   generate_proto("../src/google/protobuf/unittest_no_generic_services.proto")
+  generate_proto("google/protobuf/internal/compatibility_mode_test.proto")
+  generate_proto("google/protobuf/internal/descriptor_pool_test1.proto")
+  generate_proto("google/protobuf/internal/descriptor_pool_test2.proto")
   generate_proto("google/protobuf/internal/test_bad_identifiers.proto")
+  generate_proto("google/protobuf/internal/missing_enum_values.proto")
   generate_proto("google/protobuf/internal/more_extensions.proto")
   generate_proto("google/protobuf/internal/more_extensions_dynamic.proto")
   generate_proto("google/protobuf/internal/more_messages.proto")
@@ -102,6 +106,22 @@ def MakeTestSuite():
   import google.protobuf.internal.message_cpp_test as message_cpp_test
   import google.protobuf.internal.reflection_cpp_generated_test \
       as reflection_cpp_generated_test
+  import google.protobuf.internal.api_implementation_default_test \
+      as api_implementation_default_test
+  import google.protobuf.internal.descriptor_cpp2_test as descriptor_cpp2_test
+  import google.protobuf.internal.descriptor_python_test \
+      as descriptor_python_test
+  import google.protobuf.internal.message_factory_cpp2_test \
+      as message_factory_cpp2_test
+  import google.protobuf.internal.message_factory_cpp_test \
+      as message_factory_cpp_test
+  import google.protobuf.internal.message_factory_python_test \
+      as message_factory_python_test
+  import google.protobuf.internal.message_python_test as message_python_test
+  import google.protobuf.internal.reflection_cpp2_generated_test \
+      as reflection_cpp2_generated_test
+  import google.protobuf.internal.symbol_database_test as symbol_database_test
+  import google.protobuf.internal.text_encoding_test as text_encoding_test
 
   loader = unittest.defaultTestLoader
   suite = unittest.TestSuite()
@@ -110,7 +130,23 @@ def MakeTestSuite():
                 reflection_test,
                 service_reflection_test,
                 text_format_test,
-                wire_format_test ]:
+                wire_format_test,
+                unknown_fields_test,
+                descriptor_pool_test,
+                message_factory_test,
+                message_cpp_test,
+                reflection_cpp_generated_test,
+                api_implementation_default_test,
+                descriptor_cpp2_test,
+                descriptor_python_test,
+                message_factory_cpp2_test,
+                message_factory_cpp_test,
+                message_factory_python_test,
+                message_python_test,
+                reflection_cpp2_generated_test,
+                symbol_database_test,
+                text_encoding_test ]:
+
     suite.addTest(loader.loadTestsFromModule(test))
 
   return suite

+ 20 - 4
src/Makefile.am

@@ -40,11 +40,13 @@ MAINTAINERCLEANFILES =   \
 nobase_include_HEADERS =                                        \
   google/protobuf/stubs/atomicops.h                             \
   google/protobuf/stubs/atomicops_internals_arm_gcc.h           \
+  google/protobuf/stubs/atomicops_internals_arm64_gcc.h         \
   google/protobuf/stubs/atomicops_internals_arm_qnx.h           \
   google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
   google/protobuf/stubs/atomicops_internals_macosx.h            \
   google/protobuf/stubs/atomicops_internals_mips_gcc.h          \
   google/protobuf/stubs/atomicops_internals_pnacl.h             \
+  google/protobuf/stubs/atomicops_internals_tsan.h              \
   google/protobuf/stubs/atomicops_internals_x86_gcc.h           \
   google/protobuf/stubs/atomicops_internals_x86_msvc.h          \
   google/protobuf/stubs/common.h                                \
@@ -73,6 +75,7 @@ nobase_include_HEADERS =                                        \
   google/protobuf/io/coded_stream.h                             \
   $(GZHEADERS)                                                  \
   google/protobuf/io/printer.h                                  \
+  google/protobuf/io/strtod.h                                   \
   google/protobuf/io/tokenizer.h                                \
   google/protobuf/io/zero_copy_stream.h                         \
   google/protobuf/io/zero_copy_stream_impl.h                    \
@@ -97,7 +100,7 @@ libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/stubs/common.cc                              \
   google/protobuf/stubs/once.cc                                \
   google/protobuf/stubs/hash.h                                 \
-  google/protobuf/stubs/map-util.h                             \
+  google/protobuf/stubs/map_util.h                             \
   google/protobuf/stubs/stl_util.h                             \
   google/protobuf/stubs/stringprintf.cc                        \
   google/protobuf/stubs/stringprintf.h                         \
@@ -134,6 +137,7 @@ libprotobuf_la_SOURCES =                                       \
   google/protobuf/wire_format.cc                               \
   google/protobuf/io/gzip_stream.cc                            \
   google/protobuf/io/printer.cc                                \
+  google/protobuf/io/strtod.cc                                 \
   google/protobuf/io/tokenizer.cc                              \
   google/protobuf/io/zero_copy_stream_impl.cc                  \
   google/protobuf/compiler/importer.cc                         \
@@ -174,6 +178,8 @@ libprotoc_la_SOURCES =                                         \
   google/protobuf/compiler/cpp/cpp_service.h                   \
   google/protobuf/compiler/cpp/cpp_string_field.cc             \
   google/protobuf/compiler/cpp/cpp_string_field.h              \
+  google/protobuf/compiler/java/java_context.cc                \
+  google/protobuf/compiler/java/java_context.h                 \
   google/protobuf/compiler/java/java_enum.cc                   \
   google/protobuf/compiler/java/java_enum.h                    \
   google/protobuf/compiler/java/java_enum_field.cc             \
@@ -185,14 +191,22 @@ libprotoc_la_SOURCES =                                         \
   google/protobuf/compiler/java/java_file.cc                   \
   google/protobuf/compiler/java/java_file.h                    \
   google/protobuf/compiler/java/java_generator.cc              \
+  google/protobuf/compiler/java/java_generator_factory.cc      \
+  google/protobuf/compiler/java/java_generator_factory.h       \
   google/protobuf/compiler/java/java_helpers.cc                \
   google/protobuf/compiler/java/java_helpers.h                 \
+  google/protobuf/compiler/java/java_lazy_message_field.cc     \
+  google/protobuf/compiler/java/java_lazy_message_field.h      \
   google/protobuf/compiler/java/java_message.cc                \
   google/protobuf/compiler/java/java_message.h                 \
   google/protobuf/compiler/java/java_message_field.cc          \
   google/protobuf/compiler/java/java_message_field.h           \
+  google/protobuf/compiler/java/java_name_resolver.cc          \
+  google/protobuf/compiler/java/java_name_resolver.h           \
   google/protobuf/compiler/java/java_primitive_field.cc        \
   google/protobuf/compiler/java/java_primitive_field.h         \
+  google/protobuf/compiler/java/java_shared_code_generator.cc  \
+  google/protobuf/compiler/java/java_shared_code_generator.h   \
   google/protobuf/compiler/java/java_service.cc                \
   google/protobuf/compiler/java/java_service.h                 \
   google/protobuf/compiler/java/java_string_field.cc           \
@@ -229,9 +243,10 @@ EXTRA_DIST =                                                   \
   google/protobuf/io/gzip_stream.h                             \
   google/protobuf/io/gzip_stream_unittest.sh                   \
   google/protobuf/testdata/golden_message                      \
+  google/protobuf/testdata/golden_message_oneof_implemented    \
   google/protobuf/testdata/golden_packed_fields_message        \
-  google/protobuf/testdata/text_format_unittest_data.txt       \
-  google/protobuf/testdata/text_format_unittest_extensions_data.txt  \
+  google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt  \
+  google/protobuf/testdata/text_format_unittest_extensions_data.txt         \
   google/protobuf/package_info.h                               \
   google/protobuf/io/package_info.h                            \
   google/protobuf/compiler/package_info.h                      \
@@ -352,7 +367,8 @@ nodist_protobuf_test_SOURCES = $(protoc_outputs)
 
 # Run cpp_unittest again with PROTOBUF_TEST_NO_DESCRIPTORS defined.
 protobuf_lazy_descriptor_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la \
-                      $(top_builddir)/gtest/lib/libgtest.la       \
+                      libprotoc.la                                   \
+                      $(top_builddir)/gtest/lib/libgtest.la          \
                       $(top_builddir)/gtest/lib/libgtest_main.la
 protobuf_lazy_descriptor_test_CPPFLAGS = -I$(top_srcdir)/gtest/include    \
                                          -I$(top_builddir)/gtest/include  \

+ 6 - 2
src/google/protobuf/compiler/code_generator.cc

@@ -44,6 +44,11 @@ namespace compiler {
 CodeGenerator::~CodeGenerator() {}
 GeneratorContext::~GeneratorContext() {}
 
+io::ZeroCopyOutputStream*
+GeneratorContext::OpenForAppend(const string& filename) {
+  return NULL;
+}
+
 io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
     const string& filename, const string& insertion_point) {
   GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
@@ -58,8 +63,7 @@ void GeneratorContext::ListParsedFiles(
 // Parses a set of comma-delimited name/value pairs.
 void ParseGeneratorParameter(const string& text,
                              vector<pair<string, string> >* output) {
-  vector<string> parts;
-  SplitStringUsing(text, ",", &parts);
+  vector<string> parts = Split(text, ",", true);
 
   for (int i = 0; i < parts.size(); i++) {
     string::size_type equals_pos = parts[i].find_first_of('=');

+ 3 - 0
src/google/protobuf/compiler/code_generator.h

@@ -104,6 +104,9 @@ class LIBPROTOC_EXPORT GeneratorContext {
   // contain "." or ".." components.
   virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0;
 
+  // Similar to Open() but the output will be appended to the file if exists
+  virtual io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
+
   // Creates a ZeroCopyOutputStream which will insert code into the given file
   // at the given insertion point.  See plugin.proto (plugin.pb.h) for more
   // information on insertion points.  The default implementation

+ 180 - 14
src/google/protobuf/compiler/command_line_interface.cc

@@ -49,8 +49,10 @@
 #include <ctype.h>
 
 #include <google/protobuf/stubs/hash.h>
+#include <memory>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/plugin.pb.h>
@@ -64,7 +66,7 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 
@@ -160,8 +162,7 @@ bool VerifyDirectoryExists(const string& path) {
 // directories listed in |filename|.
 bool TryCreateParentDirectory(const string& prefix, const string& filename) {
   // Recursively create parent directories to the output file.
-  vector<string> parts;
-  SplitStringUsing(filename, "/", &parts);
+  vector<string> parts = Split(filename, "/", true);
   string path_so_far = prefix;
   for (int i = 0; i < parts.size() - 1; i++) {
     path_so_far += parts[i];
@@ -252,6 +253,7 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
 
   // implements GeneratorContext --------------------------------------
   io::ZeroCopyOutputStream* Open(const string& filename);
+  io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
   io::ZeroCopyOutputStream* OpenForInsert(
       const string& filename, const string& insertion_point);
   void ListParsedFiles(vector<const FileDescriptor*>* output) {
@@ -271,7 +273,8 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
 class CommandLineInterface::MemoryOutputStream
     : public io::ZeroCopyOutputStream {
  public:
-  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename);
+  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
+                     bool append_mode);
   MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
                      const string& insertion_point);
   virtual ~MemoryOutputStream();
@@ -290,6 +293,9 @@ class CommandLineInterface::MemoryOutputStream
   // The string we're building.
   string data_;
 
+  // Whether we should append the output stream to the existing file.
+  bool append_mode_;
+
   // StringOutputStream writing to data_.
   scoped_ptr<io::StringOutputStream> inner_;
 };
@@ -434,7 +440,13 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
 
 io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
     const string& filename) {
-  return new MemoryOutputStream(this, filename);
+  return new MemoryOutputStream(this, filename, false);
+}
+
+io::ZeroCopyOutputStream*
+CommandLineInterface::GeneratorContextImpl::OpenForAppend(
+    const string& filename) {
+  return new MemoryOutputStream(this, filename, true);
 }
 
 io::ZeroCopyOutputStream*
@@ -446,9 +458,10 @@ CommandLineInterface::GeneratorContextImpl::OpenForInsert(
 // -------------------------------------------------------------------
 
 CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
-    GeneratorContextImpl* directory, const string& filename)
+    GeneratorContextImpl* directory, const string& filename, bool append_mode)
     : directory_(directory),
       filename_(filename),
+      append_mode_(append_mode),
       inner_(new io::StringOutputStream(&data_)) {
 }
 
@@ -471,8 +484,12 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
   if (insertion_point_.empty()) {
     // This was just a regular Open().
     if (*map_slot != NULL) {
-      cerr << filename_ << ": Tried to write the same file twice." << endl;
-      directory_->had_error_ = true;
+      if (append_mode_) {
+        (*map_slot)->append(data_);
+      } else {
+        cerr << filename_ << ": Tried to write the same file twice." << endl;
+        directory_->had_error_ = true;
+      }
       return;
     }
 
@@ -565,6 +582,7 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
 
 CommandLineInterface::CommandLineInterface()
   : mode_(MODE_COMPILE),
+    print_mode_(PRINT_NONE),
     error_format_(ERROR_FORMAT_GCC),
     imports_in_descriptor_set_(false),
     source_info_in_descriptor_set_(false),
@@ -632,7 +650,9 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
   // Parse each file.
   for (int i = 0; i < input_files_.size(); i++) {
     // Import the file.
+    importer.AddUnusedImportTrackFile(input_files_[i]);
     const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
+    importer.ClearUnusedImportTrackFiles();
     if (parsed_file == NULL) return 1;
     parsed_files.push_back(parsed_file);
 
@@ -721,6 +741,25 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
     }
   }
 
+  if (mode_ == MODE_PRINT) {
+    switch (print_mode_) {
+      case PRINT_FREE_FIELDS:
+        for (int i = 0; i < parsed_files.size(); ++i) {
+          const FileDescriptor* fd = parsed_files[i];
+          for (int j = 0; j < fd->message_type_count(); ++j) {
+            PrintFreeFieldNumbers(fd->message_type(j));
+          }
+        }
+        break;
+      case PRINT_NONE:
+        GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
+                     "flag parsing in the CommonadLineInterface.";
+        return 1;
+
+      // Do not add a default case.
+    }
+  }
+
   return 0;
 }
 
@@ -735,6 +774,7 @@ void CommandLineInterface::Clear() {
   descriptor_set_name_.clear();
 
   mode_ = MODE_COMPILE;
+  print_mode_ = PRINT_NONE;
   imports_in_descriptor_set_ = false;
   source_info_in_descriptor_set_ = false;
   disallow_services_ = false;
@@ -889,7 +929,8 @@ bool CommandLineInterface::ParseArgument(const char* arg,
       *name == "--include_imports" ||
       *name == "--include_source_info" ||
       *name == "--version" ||
-      *name == "--decode_raw") {
+      *name == "--decode_raw" ||
+      *name == "--print_free_field_numbers") {
     // HACK:  These are the only flags that don't take a value.
     //   They probably should not be hard-coded like this but for now it's
     //   not worth doing better.
@@ -919,8 +960,8 @@ CommandLineInterface::InterpretArgument(const string& name,
     // Java's -classpath (and some other languages) delimits path components
     // with colons.  Let's accept that syntax too just to make things more
     // intuitive.
-    vector<string> parts;
-    SplitStringUsing(value, kPathSeparator, &parts);
+    vector<string> parts = Split(
+        value, kPathSeparator, true);
 
     for (int i = 0; i < parts.size(); i++) {
       string virtual_path;
@@ -1061,6 +1102,19 @@ CommandLineInterface::InterpretArgument(const string& name,
 
     plugins_[plugin_name] = path;
 
+  } else if (name == "--print_free_field_numbers") {
+    if (mode_ != MODE_COMPILE) {
+      cerr << "Cannot use " << name << " and use --encode, --decode or print "
+           << "other info at the same time." << endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
+      cerr << "Cannot use " << name
+           << " and generate code or descriptors at the same time." << endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    mode_ = MODE_PRINT;
+    print_mode_ = PRINT_FREE_FIELDS;
   } else {
     // Some other flag.  Look it up in the generators list.
     const GeneratorInfo* generator_info =
@@ -1082,8 +1136,8 @@ CommandLineInterface::InterpretArgument(const string& name,
     } else {
       // It's an output flag.  Add it to the output directives.
       if (mode_ != MODE_COMPILE) {
-        cerr << "Cannot use --encode or --decode and generate code at the "
-                "same time." << endl;
+        cerr << "Cannot use --encode, --decode or print .proto info and "
+                "generate code at the same time." << endl;
         return PARSE_ARGUMENT_FAIL;
       }
 
@@ -1151,7 +1205,12 @@ void CommandLineInterface::PrintHelpText() {
 "                              well as surrounding comments.\n"
 "  --error_format=FORMAT       Set the format in which to print errors.\n"
 "                              FORMAT may be 'gcc' (the default) or 'msvs'\n"
-"                              (Microsoft Visual Studio format)." << endl;
+"                              (Microsoft Visual Studio format).\n"
+"  --print_free_field_numbers  Print the free field numbers of the messages\n"
+"                              defined in the given proto files. Groups share\n"
+"                              the same field number space with the parent \n"
+"                              message. Extension ranges are counted as \n"
+"                              occupied fields numbers."  << endl;
   if (!plugin_prefix_.empty()) {
     cerr <<
 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
@@ -1431,6 +1490,113 @@ void CommandLineInterface::GetTransitiveDependencies(
   }
 }
 
+namespace {
+
+// Utility function for PrintFreeFieldNumbers.
+// Stores occupied ranges into the ranges parameter, and next level of sub
+// message types into the nested_messages parameter.  The FieldRange is left
+// inclusive, right exclusive. i.e. [a, b).
+//
+// Nested Messages:
+// Note that it only stores the nested message type, iff the nested type is
+// either a direct child of the given descriptor, or the nested type is a
+// decendent of the given descriptor and all the nodes between the
+// nested type and the given descriptor are group types. e.g.
+//
+// message Foo {
+//   message Bar {
+//     message NestedBar {}
+//   }
+//   group Baz = 1 {
+//     group NestedBazGroup = 2 {
+//       message Quz {
+//         message NestedQuz {}
+//       }
+//     }
+//     message NestedBaz {}
+//   }
+// }
+//
+// In this case, Bar, Quz and NestedBaz will be added into the nested types.
+// Since free field numbers of group types will not be printed, this makes sure
+// the nested message types in groups will not be dropped. The nested_messages
+// parameter will contain the direct children (when groups are ignored in the
+// tree) of the given descriptor for the caller to traverse. The declaration
+// order of the nested messages is also preserved.
+typedef pair<int, int> FieldRange;
+void GatherOccupiedFieldRanges(const Descriptor* descriptor,
+                               set<FieldRange>* ranges,
+                               vector<const Descriptor*>* nested_messages) {
+  set<const Descriptor*> groups;
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* fd = descriptor->field(i);
+    ranges->insert(FieldRange(fd->number(), fd->number() + 1));
+    if (fd->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(fd->message_type());
+    }
+  }
+  for (int i = 0; i < descriptor->extension_range_count(); ++i) {
+    ranges->insert(FieldRange(descriptor->extension_range(i)->start,
+                              descriptor->extension_range(i)->end));
+  }
+  // Handle the nested messages/groups in declaration order to make it
+  // post-order strict.
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    const Descriptor* nested_desc = descriptor->nested_type(i);
+    if (groups.find(nested_desc) != groups.end()) {
+      GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
+    } else {
+      nested_messages->push_back(nested_desc);
+    }
+  }
+}
+
+// Utility function for PrintFreeFieldNumbers.
+// Actually prints the formatted free field numbers for given message name and
+// occupied ranges.
+void FormatFreeFieldNumbers(const string& name,
+                            const set<FieldRange>& ranges) {
+  string output;
+  StringAppendF(&output, "%-35s free:", name.c_str());
+  int next_free_number = 1;
+  for (set<FieldRange>::iterator i = ranges.begin();
+       i != ranges.end(); ++i) {
+    // This happens when groups re-use parent field numbers, in which
+    // case we skip the FieldRange entirely.
+    if (next_free_number >= i->second) continue;
+
+    if (next_free_number < i->first) {
+      if (next_free_number + 1 == i->first) {
+        // Singleton
+        StringAppendF(&output, " %d", next_free_number);
+      } else {
+        // Range
+        StringAppendF(&output, " %d-%d", next_free_number, i->first - 1);
+      }
+    }
+    next_free_number = i->second;
+  }
+  if (next_free_number <= FieldDescriptor::kMaxNumber) {
+    StringAppendF(&output, " %d-INF", next_free_number);
+  }
+  cout << output << endl;
+}
+
+}  // namespace
+
+void CommandLineInterface::PrintFreeFieldNumbers(
+    const Descriptor* descriptor) {
+  set<FieldRange> ranges;
+  vector<const Descriptor*> nested_messages;
+  GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
+
+  for (int i = 0; i < nested_messages.size(); ++i) {
+    PrintFreeFieldNumbers(nested_messages[i]);
+  }
+  FormatFreeFieldNumbers(descriptor->full_name(), ranges);
+}
+
+
 
 }  // namespace compiler
 }  // namespace protobuf

+ 27 - 2
src/google/protobuf/compiler/command_line_interface.h

@@ -48,8 +48,9 @@
 namespace google {
 namespace protobuf {
 
-class FileDescriptor;        // descriptor.h
+class Descriptor;            // descriptor.h
 class DescriptorPool;        // descriptor.h
+class FileDescriptor;        // descriptor.h
 class FileDescriptorProto;   // descriptor.pb.h
 template<typename T> class RepeatedPtrField;  // repeated_field.h
 
@@ -259,6 +260,22 @@ class LIBPROTOC_EXPORT CommandLineInterface {
       set<const FileDescriptor*>* already_seen,
       RepeatedPtrField<FileDescriptorProto>* output);
 
+  // Implements the --print_free_field_numbers. This function prints free field
+  // numbers into stdout for the message and it's nested message types in
+  // post-order, i.e. nested types first. Printed range are left-right
+  // inclusive, i.e. [a, b].
+  //
+  // Groups:
+  // For historical reasons, groups are considered to share the same
+  // field number space with the parent message, thus it will not print free
+  // field numbers for groups. The field numbers used in the groups are
+  // excluded in the free field numbers of the parent message.
+  //
+  // Extension Ranges:
+  // Extension ranges are considered ocuppied field numbers and they will not be
+  // listed as free numbers in the output.
+  void PrintFreeFieldNumbers(const Descriptor* descriptor);
+
   // -----------------------------------------------------------------
 
   // The name of the executable as invoked (i.e. argv[0]).
@@ -295,11 +312,19 @@ class LIBPROTOC_EXPORT CommandLineInterface {
   enum Mode {
     MODE_COMPILE,  // Normal mode:  parse .proto files and compile them.
     MODE_ENCODE,   // --encode:  read text from stdin, write binary to stdout.
-    MODE_DECODE    // --decode:  read binary from stdin, write text to stdout.
+    MODE_DECODE,   // --decode:  read binary from stdin, write text to stdout.
+    MODE_PRINT,    // Print mode: print info of the given .proto files and exit.
   };
 
   Mode mode_;
 
+  enum PrintMode {
+    PRINT_NONE,               // Not in MODE_PRINT
+    PRINT_FREE_FIELDS,        // --print_free_fields
+  };
+
+  PrintMode print_mode_;
+
   enum ErrorFormat {
     ERROR_FORMAT_GCC,   // GCC error output format (default).
     ERROR_FORMAT_MSVS   // Visual Studio output (--error_format=msvs).

+ 104 - 23
src/google/protobuf/compiler/command_line_interface_unittest.cc

@@ -40,6 +40,7 @@
 #else
 #include <unistd.h>
 #endif
+#include <memory>
 #include <vector>
 
 #include <google/protobuf/descriptor.pb.h>
@@ -126,6 +127,9 @@ class CommandLineInterfaceTest : public testing::Test {
   void ExpectErrorSubstringWithZeroReturnCode(
       const string& expected_substring);
 
+  // Checks that the captured stdout is the same as the expected_text.
+  void ExpectCapturedStdout(const string& expected_text);
+
   // Returns true if ExpectErrorSubstring(expected_substring) would pass, but
   // does not fail otherwise.
   bool HasAlternateErrorSubstring(const string& expected_substring);
@@ -182,6 +186,9 @@ class CommandLineInterfaceTest : public testing::Test {
   // The captured stderr output.
   string error_text_;
 
+  // The captured stdout.
+  string captured_stdout_;
+
   // Pointers which need to be deleted later.
   vector<CodeGenerator*> mock_generators_to_delete_;
 
@@ -224,7 +231,7 @@ void CommandLineInterfaceTest::SetUp() {
   }
 
   // Create the temp directory.
-  GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE));
+  GOOGLE_CHECK_OK(File::CreateDir(temp_directory_, 0777));
 
   // Register generators.
   CodeGenerator* generator = new MockCodeGenerator("test_generator");
@@ -255,8 +262,7 @@ void CommandLineInterfaceTest::TearDown() {
 }
 
 void CommandLineInterfaceTest::Run(const string& command) {
-  vector<string> args;
-  SplitStringUsing(command, " ", &args);
+  vector<string> args = Split(command, " ", true);
 
   if (!disallow_plugins_) {
     cli_.AllowPlugins("prefix-");
@@ -295,18 +301,20 @@ void CommandLineInterfaceTest::Run(const string& command) {
     }
   }
 
-  scoped_array<const char*> argv(new const char*[args.size()]);
+  scoped_array<const char*> argv(new const char* [args.size()]);
 
   for (int i = 0; i < args.size(); i++) {
     args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
     argv[i] = args[i].c_str();
   }
 
+  CaptureTestStdout();
   CaptureTestStderr();
 
   return_code_ = cli_.Run(args.size(), argv.get());
 
   error_text_ = GetCapturedTestStderr();
+  captured_stdout_ = GetCapturedTestStdout();
 }
 
 // -------------------------------------------------------------------
@@ -318,16 +326,20 @@ void CommandLineInterfaceTest::CreateTempFile(
   string::size_type slash_pos = name.find_last_of('/');
   if (slash_pos != string::npos) {
     string dir = name.substr(0, slash_pos);
-    File::RecursivelyCreateDir(temp_directory_ + "/" + dir, 0777);
+    if (!File::Exists(temp_directory_ + "/" + dir)) {
+      GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir,
+                                          0777));
+    }
   }
 
   // Write file.
   string full_name = temp_directory_ + "/" + name;
-  File::WriteStringToFileOrDie(contents, full_name);
+  GOOGLE_CHECK_OK(File::SetContents(full_name, contents, true));
 }
 
 void CommandLineInterfaceTest::CreateTempDir(const string& name) {
-  File::RecursivelyCreateDir(temp_directory_ + "/" + name, 0777);
+  GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + name,
+                                      0777));
 }
 
 // -------------------------------------------------------------------
@@ -414,14 +426,18 @@ void CommandLineInterfaceTest::ReadDescriptorSet(
     const string& filename, FileDescriptorSet* descriptor_set) {
   string path = temp_directory_ + "/" + filename;
   string file_contents;
-  if (!File::ReadFileToString(path, &file_contents)) {
-    FAIL() << "File not found: " << path;
-  }
+  GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
+
   if (!descriptor_set->ParseFromString(file_contents)) {
     FAIL() << "Could not parse file contents: " << path;
   }
 }
 
+void CommandLineInterfaceTest::ExpectCapturedStdout(
+    const string& expected_text) {
+  EXPECT_EQ(expected_text, captured_stdout_);
+}
+
 // ===================================================================
 
 TEST_F(CommandLineInterfaceTest, BasicOutput) {
@@ -813,7 +829,7 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
   FileDescriptorSet descriptor_set;
   ReadDescriptorSet("descriptor_set", &descriptor_set);
   if (HasFatalFailure()) return;
-  ASSERT_EQ(1, descriptor_set.file_size());
+  EXPECT_EQ(1, descriptor_set.file_size());
   EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
   // Descriptor set should not have source code info.
   EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
@@ -838,7 +854,7 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
   FileDescriptorSet descriptor_set;
   ReadDescriptorSet("descriptor_set", &descriptor_set);
   if (HasFatalFailure()) return;
-  ASSERT_EQ(1, descriptor_set.file_size());
+  EXPECT_EQ(1, descriptor_set.file_size());
   EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
   // Source code info included.
   EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
@@ -863,7 +879,7 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
   FileDescriptorSet descriptor_set;
   ReadDescriptorSet("descriptor_set", &descriptor_set);
   if (HasFatalFailure()) return;
-  ASSERT_EQ(2, descriptor_set.file_size());
+  EXPECT_EQ(2, descriptor_set.file_size());
   if (descriptor_set.file(0).name() == "bar.proto") {
     std::swap(descriptor_set.mutable_file()->mutable_data()[0],
               descriptor_set.mutable_file()->mutable_data()[1]);
@@ -894,7 +910,7 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
   FileDescriptorSet descriptor_set;
   ReadDescriptorSet("descriptor_set", &descriptor_set);
   if (HasFatalFailure()) return;
-  ASSERT_EQ(2, descriptor_set.file_size());
+  EXPECT_EQ(2, descriptor_set.file_size());
   if (descriptor_set.file(0).name() == "bar.proto") {
     std::swap(descriptor_set.mutable_file()->mutable_data()[0],
               descriptor_set.mutable_file()->mutable_data()[1]);
@@ -1393,6 +1409,70 @@ TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) {
   ExpectErrorText("Missing value for flag: --test_out\n");
 }
 
+TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) {
+  CreateTempFile(
+      "foo.proto",
+      "syntax = \"proto2\";\n"
+      "package foo;\n"
+      "message Foo {\n"
+      "  optional int32 a = 2;\n"
+      "  optional string b = 4;\n"
+      "  optional string c = 5;\n"
+      "  optional int64 d = 8;\n"
+      "  optional double e = 10;\n"
+      "}\n");
+  CreateTempFile(
+      "bar.proto",
+      "syntax = \"proto2\";\n"
+      "message Bar {\n"
+      "  optional int32 a = 2;\n"
+      "  extensions 4 to 5;\n"
+      "  optional int64 d = 8;\n"
+      "  extensions 10;\n"
+      "}\n");
+  CreateTempFile(
+      "baz.proto",
+      "syntax = \"proto2\";\n"
+      "message Baz {\n"
+      "  optional int32 a = 2;\n"
+      "  optional int64 d = 8;\n"
+      "  extensions 15 to max;\n"  // unordered.
+      "  extensions 13;\n"
+      "  extensions 10 to 12;\n"
+      "  extensions 5;\n"
+      "  extensions 4;\n"
+      "}\n");
+  CreateTempFile(
+      "quz.proto",
+      "syntax = \"proto2\";\n"
+      "message Quz {\n"
+      "  message Foo {}\n"  // nested message
+      "  optional int32 a = 2;\n"
+      "  optional group C = 4 {\n"
+      "    optional int32 d = 5;\n"
+      "  }\n"
+      "  extensions 8 to 10;\n"
+      "  optional group E = 11 {\n"
+      "    optional int32 f = 9;\n"    // explicitly reuse extension range 8-10
+      "    optional group G = 15 {\n"  // nested group
+      "      message Foo {}\n"         // nested message inside nested group
+      "    }\n"
+      "  }\n"
+      "}\n");
+
+  Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir "
+      "foo.proto bar.proto baz.proto quz.proto");
+
+  ExpectNoErrors();
+  ExpectCapturedStdout(
+      "foo.Foo                             free: 1 3 6-7 9 11-INF\n"
+      "Bar                                 free: 1 3 6-7 9 11-INF\n"
+      "Baz                                 free: 1 3 6-7 9 14\n"
+      "Quz.Foo                             free: 1-INF\n"
+      "Quz.E.G.Foo                         free: 1-INF\n"
+      "Quz                                 free: 1 3 6-7 12-14 16-INF\n");
+}
+
 // ===================================================================
 
 // Test for --encode and --decode.  Note that it would be easier to do this
@@ -1412,7 +1492,7 @@ class EncodeDecodeTest : public testing::Test {
 
   void RedirectStdinFromText(const string& input) {
     string filename = TestTempDir() + "/test_stdin";
-    File::WriteStringToFileOrDie(input, filename);
+    GOOGLE_CHECK_OK(File::SetContents(filename, input, true));
     GOOGLE_CHECK(RedirectStdinFromFile(filename));
   }
 
@@ -1446,7 +1526,7 @@ class EncodeDecodeTest : public testing::Test {
     SplitStringUsing(command, " ", &args);
     args.push_back("--proto_path=" + TestSourceDir());
 
-    scoped_array<const char*> argv(new const char*[args.size()]);
+    scoped_array<const char*> argv(new const char* [args.size()]);
     for (int i = 0; i < args.size(); i++) {
       argv[i] = args[i].c_str();
     }
@@ -1467,7 +1547,7 @@ class EncodeDecodeTest : public testing::Test {
 
   void ExpectStdoutMatchesBinaryFile(const string& filename) {
     string expected_output;
-    ASSERT_TRUE(File::ReadFileToString(filename, &expected_output));
+    GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
 
     // Don't use EXPECT_EQ because we don't want to print raw binary data to
     // stdout on failure.
@@ -1476,7 +1556,7 @@ class EncodeDecodeTest : public testing::Test {
 
   void ExpectStdoutMatchesTextFile(const string& filename) {
     string expected_output;
-    ASSERT_TRUE(File::ReadFileToString(filename, &expected_output));
+    GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
 
     ExpectStdoutMatchesText(expected_output);
   }
@@ -1496,22 +1576,23 @@ class EncodeDecodeTest : public testing::Test {
 };
 
 TEST_F(EncodeDecodeTest, Encode) {
-  RedirectStdinFromFile(TestSourceDir() +
-    "/google/protobuf/testdata/text_format_unittest_data.txt");
+  RedirectStdinFromFile(TestSourceDir() + "/google/protobuf/"
+    "testdata/text_format_unittest_data_oneof_implemented.txt");
   EXPECT_TRUE(Run("google/protobuf/unittest.proto "
                   "--encode=protobuf_unittest.TestAllTypes"));
   ExpectStdoutMatchesBinaryFile(TestSourceDir() +
-    "/google/protobuf/testdata/golden_message");
+    "/google/protobuf/testdata/golden_message_oneof_implemented");
   ExpectStderrMatchesText("");
 }
 
 TEST_F(EncodeDecodeTest, Decode) {
   RedirectStdinFromFile(TestSourceDir() +
-    "/google/protobuf/testdata/golden_message");
+    "/google/protobuf/testdata/golden_message_oneof_implemented");
   EXPECT_TRUE(Run("google/protobuf/unittest.proto "
                   "--decode=protobuf_unittest.TestAllTypes"));
   ExpectStdoutMatchesTextFile(TestSourceDir() +
-    "/google/protobuf/testdata/text_format_unittest_data.txt");
+    "/google/protobuf/"
+    "testdata/text_format_unittest_data_oneof_implemented.txt");
   ExpectStderrMatchesText("");
 }
 

+ 4 - 4
src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc

@@ -48,7 +48,7 @@
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
@@ -93,9 +93,9 @@ class MockGeneratorContext : public GeneratorContext {
       << "Generator failed to generate file: " << virtual_filename;
 
     string actual_contents;
-    File::ReadFileToStringOrDie(
-      TestSourceDir() + "/" + physical_filename,
-      &actual_contents);
+    GOOGLE_CHECK_OK(
+        File::GetContents(TestSourceDir() + "/" + physical_filename,
+                          &actual_contents, true));
     EXPECT_TRUE(actual_contents == *expected_contents)
       << physical_filename << " needs to be regenerated.  Please run "
          "generate_descriptor_proto.sh and add this file "

+ 41 - 11
src/google/protobuf/compiler/cpp/cpp_enum.cc

@@ -45,11 +45,27 @@ namespace protobuf {
 namespace compiler {
 namespace cpp {
 
+namespace {
+// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
+// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// generation of the GOOGLE_ARRAYSIZE constant.
+bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
+  int32 max_value = descriptor->value(0)->number();
+  for (int i = 0; i < descriptor->value_count(); i++) {
+    if (descriptor->value(i)->number() > max_value) {
+      max_value = descriptor->value(i)->number();
+    }
+  }
+  return max_value != kint32max;
+}
+}  // namespace
+
 EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
                              const Options& options)
   : descriptor_(descriptor),
     classname_(ClassName(descriptor, false)),
-    options_(options) {
+    options_(options),
+    generate_array_size_(ShouldGenerateArraySize(descriptor)) {
 }
 
 EnumGenerator::~EnumGenerator() {}
@@ -67,7 +83,10 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
 
   for (int i = 0; i < descriptor_->value_count(); i++) {
     vars["name"] = descriptor_->value(i)->name();
-    vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+    // In C++, an value of -2147483648 gets interpreted as the negative of
+    // 2147483648, and since 2147483648 can't fit in an integer, this produces a
+    // compiler warning.  This works around that issue.
+    vars["number"] = Int32ToString(descriptor_->value(i)->number());
     vars["prefix"] = (descriptor_->containing_type() == NULL) ?
       "" : classname_ + "_";
 
@@ -97,9 +116,13 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
   printer->Print(vars,
     "$dllexport$bool $classname$_IsValid(int value);\n"
     "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
-    "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"
-    "const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n"
-    "\n");
+    "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n");
+
+  if (generate_array_size_) {
+    printer->Print(vars,
+      "const int $prefix$$short_name$_ARRAYSIZE = "
+      "$prefix$$short_name$_MAX + 1;\n\n");
+  }
 
   if (HasDescriptorMethods(descriptor_->file())) {
     printer->Print(vars,
@@ -123,6 +146,7 @@ void EnumGenerator::
 GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
   if (HasDescriptorMethods(descriptor_->file())) {
     printer->Print(
+      "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type {};\n"
       "template <>\n"
       "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
       "  return $classname$_descriptor();\n"
@@ -150,9 +174,12 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
     "static const $nested_name$ $nested_name$_MIN =\n"
     "  $classname$_$nested_name$_MIN;\n"
     "static const $nested_name$ $nested_name$_MAX =\n"
-    "  $classname$_$nested_name$_MAX;\n"
-    "static const int $nested_name$_ARRAYSIZE =\n"
-    "  $classname$_$nested_name$_ARRAYSIZE;\n");
+    "  $classname$_$nested_name$_MAX;\n");
+  if (generate_array_size_) {
+    printer->Print(vars,
+      "static const int $nested_name$_ARRAYSIZE =\n"
+      "  $classname$_$nested_name$_ARRAYSIZE;\n");
+  }
 
   if (HasDescriptorMethods(descriptor_->file())) {
     printer->Print(vars,
@@ -218,7 +245,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
        iter != numbers.end(); ++iter) {
     printer->Print(
       "    case $number$:\n",
-      "number", SimpleItoa(*iter));
+      "number", Int32ToString(*iter));
   }
 
   printer->Print(vars,
@@ -245,8 +272,11 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
     }
     printer->Print(vars,
       "const $classname$ $parent$::$nested_name$_MIN;\n"
-      "const $classname$ $parent$::$nested_name$_MAX;\n"
-      "const int $parent$::$nested_name$_ARRAYSIZE;\n");
+      "const $classname$ $parent$::$nested_name$_MAX;\n");
+    if (generate_array_size_) {
+      printer->Print(vars,
+        "const int $parent$::$nested_name$_ARRAYSIZE;\n");
+    }
 
     printer->Print("#endif  // _MSC_VER\n");
   }

+ 2 - 0
src/google/protobuf/compiler/cpp/cpp_enum.h

@@ -89,6 +89,8 @@ class EnumGenerator {
   const EnumDescriptor* descriptor_;
   string classname_;
   Options options_;
+  // whether to generate the *_ARRAYSIZE constant.
+  bool generate_array_size_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
 };

+ 69 - 4
src/google/protobuf/compiler/cpp/cpp_enum_field.cc

@@ -51,7 +51,8 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
   SetCommonFieldVariables(descriptor, variables, options);
   const EnumValueDescriptor* default_value = descriptor->default_value_enum();
   (*variables)["type"] = ClassName(descriptor->enum_type(), true);
-  (*variables)["default"] = SimpleItoa(default_value->number());
+  (*variables)["default"] = Int32ToString(default_value->number());
+  (*variables)["full_name"] = descriptor->full_name();
 }
 
 }  // namespace
@@ -83,12 +84,14 @@ void EnumFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline $type$ $classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return static_cast< $type$ >($name$_);\n"
     "}\n"
     "inline void $classname$::set_$name$($type$ value) {\n"
     "  assert($type$_IsValid(value));\n"
     "  set_has_$name$();\n"
     "  $name$_ = value;\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
 }
 
@@ -121,10 +124,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
     "       input, &value)));\n"
     "if ($type$_IsValid(value)) {\n"
     "  set_$name$(static_cast< $type$ >(value));\n");
-  if (HasUnknownFields(descriptor_->file())) {
+  if (UseUnknownFieldSet(descriptor_->file())) {
     printer->Print(variables_,
       "} else {\n"
       "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+  } else {
+    printer->Print(
+      "} else {\n"
+      "  unknown_fields_stream.WriteVarint32(tag);\n"
+      "  unknown_fields_stream.WriteVarint32(value);\n");
   }
   printer->Print(variables_,
     "}\n");
@@ -153,6 +161,52 @@ GenerateByteSize(io::Printer* printer) const {
 
 // ===================================================================
 
+EnumOneofFieldGenerator::
+EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options)
+  : EnumFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
+
+void EnumOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+  printer->Print(variables_,
+    "inline $type$ $classname$::$name$() const {\n"
+    "  if (has_$name$()) {\n"
+    "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
+    "  }\n"
+    "  return static_cast< $type$ >($default$);\n"
+    "}\n"
+    "inline void $classname$::set_$name$($type$ value) {\n"
+    "  assert($type$_IsValid(value));\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "  }\n"
+    "  $oneof_prefix$$name$_ = value;\n"
+    "}\n");
+}
+
+void EnumOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
+}
+
+void EnumOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void EnumOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
+}
+
+// ===================================================================
+
 RepeatedEnumFieldGenerator::
 RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
                            const Options& options)
@@ -166,7 +220,8 @@ void RepeatedEnumFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField<int> $name$_;\n");
-  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
+  if (descriptor_->options().packed()
+      && HasGeneratedMethods(descriptor_->file())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -187,23 +242,28 @@ void RepeatedEnumFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline $type$ $classname$::$name$(int index) const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return static_cast< $type$ >($name$_.Get(index));\n"
     "}\n"
     "inline void $classname$::set_$name$(int index, $type$ value) {\n"
     "  assert($type$_IsValid(value));\n"
     "  $name$_.Set(index, value);\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
     "inline void $classname$::add_$name$($type$ value) {\n"
     "  assert($type$_IsValid(value));\n"
     "  $name$_.Add(value);\n"
+    "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n");
   printer->Print(variables_,
     "inline const ::google::protobuf::RepeatedField<int>&\n"
     "$classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
     "inline ::google::protobuf::RepeatedField<int>*\n"
     "$classname$::mutable_$name$() {\n"
+    "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "}\n");
 }
@@ -238,10 +298,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
     "       input, &value)));\n"
     "if ($type$_IsValid(value)) {\n"
     "  add_$name$(static_cast< $type$ >(value));\n");
-  if (HasUnknownFields(descriptor_->file())) {
+  if (UseUnknownFieldSet(descriptor_->file())) {
     printer->Print(variables_,
       "} else {\n"
       "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+  } else {
+    printer->Print(
+      "} else {\n"
+      "  unknown_fields_stream.WriteVarint32(tag);\n"
+      "  unknown_fields_stream.WriteVarint32(value);\n");
   }
   printer->Print("}\n");
 }

+ 18 - 1
src/google/protobuf/compiler/cpp/cpp_enum_field.h

@@ -63,13 +63,30 @@ class EnumFieldGenerator : public FieldGenerator {
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
- private:
+ protected:
   const FieldDescriptor* descriptor_;
   map<string, string> variables_;
 
+ private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
 };
 
+class EnumOneofFieldGenerator : public EnumFieldGenerator {
+ public:
+  explicit EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                   const Options& options);
+  ~EnumOneofFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateClearingCode(io::Printer* printer) const;
+  void GenerateSwappingCode(io::Printer* printer) const;
+  void GenerateConstructorCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
+};
+
 class RepeatedEnumFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,

+ 26 - 2
src/google/protobuf/compiler/cpp/cpp_field.cc

@@ -33,6 +33,8 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <memory>
+
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
@@ -68,6 +70,12 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
   (*variables)["cppget"] = "Get";
 }
 
+void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
+                                  map<string, string>* variables) {
+  (*variables)["oneof_prefix"] = descriptor->containing_oneof()->name() + "_.";
+  (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
+}
+
 FieldGenerator::~FieldGenerator() {}
 
 void FieldGenerator::
@@ -84,8 +92,9 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
 
 FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
                                      const Options& options)
-  : descriptor_(descriptor),
-    field_generators_(new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+    : descriptor_(descriptor),
+      field_generators_(
+          new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
   // Construct all the FieldGenerators.
   for (int i = 0; i < descriptor->field_count(); i++) {
     field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
@@ -109,6 +118,21 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
       default:
         return new RepeatedPrimitiveFieldGenerator(field, options);
     }
+  } else if (field->containing_oneof()) {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        return new MessageOneofFieldGenerator(field, options);
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // StringOneofFieldGenerator handles unknown ctypes.
+          case FieldOptions::STRING:
+            return new StringOneofFieldGenerator(field, options);
+        }
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return new EnumOneofFieldGenerator(field, options);
+      default:
+        return new PrimitiveOneofFieldGenerator(field, options);
+    }
   } else {
     switch (field->cpp_type()) {
       case FieldDescriptor::CPPTYPE_MESSAGE:

+ 9 - 1
src/google/protobuf/compiler/cpp/cpp_field.h

@@ -36,9 +36,9 @@
 #define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
 
 #include <map>
+#include <memory>
 #include <string>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 
@@ -61,6 +61,9 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
                              map<string, string>* variables,
                              const Options& options);
 
+void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
+                                  map<string, string>* variables);
+
 class FieldGenerator {
  public:
   FieldGenerator() {}
@@ -71,6 +74,11 @@ class FieldGenerator {
   // class.
   virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
 
+  // Generate static default variable for this field. These are placed inside
+  // the message class. Most field types don't need this, so the default
+  // implementation is empty.
+  virtual void GenerateStaticMembers(io::Printer* printer) const {}
+
   // Generate prototypes for all of the accessor functions related to this
   // field.  These are placed inside the class definition.
   virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;

+ 37 - 24
src/google/protobuf/compiler/cpp/cpp_file.cc

@@ -33,6 +33,9 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_file.h>
+#include <memory>
+#include <set>
+
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
 #include <google/protobuf/compiler/cpp/cpp_service.h>
 #include <google/protobuf/compiler/cpp/cpp_extension.h>
@@ -50,18 +53,17 @@ namespace cpp {
 
 // ===================================================================
 
-FileGenerator::FileGenerator(const FileDescriptor* file,
-                             const Options& options)
-  : file_(file),
-    message_generators_(
-      new scoped_ptr<MessageGenerator>[file->message_type_count()]),
-    enum_generators_(
-      new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
-    service_generators_(
-      new scoped_ptr<ServiceGenerator>[file->service_count()]),
-    extension_generators_(
-      new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
-    options_(options) {
+FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
+    : file_(file),
+      message_generators_(
+          new scoped_ptr<MessageGenerator>[file->message_type_count()]),
+      enum_generators_(
+          new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
+      service_generators_(
+          new scoped_ptr<ServiceGenerator>[file->service_count()]),
+      extension_generators_(
+          new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
+      options_(options) {
 
   for (int i = 0; i < file->message_type_count(); i++) {
     message_generators_[i].reset(
@@ -153,19 +155,28 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
       "#include <google/protobuf/service.h>\n");
   }
 
-  if (HasUnknownFields(file_) && file_->message_type_count() > 0) {
+  if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
     printer->Print(
       "#include <google/protobuf/unknown_field_set.h>\n");
   }
 
 
+  set<string> public_import_names;
+  for (int i = 0; i < file_->public_dependency_count(); i++) {
+    public_import_names.insert(file_->public_dependency(i)->name());
+  }
+
   for (int i = 0; i < file_->dependency_count(); i++) {
+    const string& name = file_->dependency(i)->name();
+    bool public_import = (public_import_names.count(name) != 0);
+
+
     printer->Print(
-      "#include \"$dependency$.pb.h\"\n",
-      "dependency", StripProto(file_->dependency(i)->name()));
+      "#include \"$dependency$.pb.h\"$iwyu$\n",
+      "dependency", StripProto(name),
+      "iwyu", (public_import) ? "  // IWYU pragma: export" : "");
   }
 
-
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
 
@@ -248,6 +259,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
   printer->Print(kThickSeparator);
   printer->Print("\n");
 
+
   // Generate class inline methods.
   for (int i = 0; i < file_->message_type_count(); i++) {
     if (i > 0) {
@@ -317,6 +329,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
     "filename", file_->name(),
     "basename", StripProto(file_->name()));
 
+  // Unknown fields implementation in lite mode uses StringOutputStream
+  if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+    printer->Print(
+      "#include <google/protobuf/io/zero_copy_stream_impl_lite.h>\n");
+  }
+
   if (HasDescriptorMethods(file_)) {
     printer->Print(
       "#include <google/protobuf/descriptor.h>\n"
@@ -542,17 +560,12 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
   for (int i = 0; i < file_->dependency_count(); i++) {
     const FileDescriptor* dependency = file_->dependency(i);
     // Print the namespace prefix for the dependency.
-    vector<string> dependency_package_parts;
-    SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
-    printer->Print("::");
-    for (int j = 0; j < dependency_package_parts.size(); j++) {
-      printer->Print("$name$::",
-                     "name", dependency_package_parts[j]);
-    }
+    string add_desc_name = QualifiedFileLevelSymbol(
+        dependency->package(), GlobalAddDescriptorsName(dependency->name()));
     // Call its AddDescriptors function.
     printer->Print(
       "$name$();\n",
-      "name", GlobalAddDescriptorsName(dependency->name()));
+      "name", add_desc_name);
   }
 
   if (HasDescriptorMethods(file_)) {

+ 1 - 1
src/google/protobuf/compiler/cpp/cpp_file.h

@@ -35,6 +35,7 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
 
+#include <memory>
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
@@ -85,7 +86,6 @@ class FileGenerator {
 
   // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
   vector<string> package_parts_;
-
   const Options options_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);

+ 3 - 2
src/google/protobuf/compiler/cpp/cpp_generator.cc

@@ -35,6 +35,7 @@
 #include <google/protobuf/compiler/cpp/cpp_generator.h>
 
 #include <vector>
+#include <memory>
 #include <utility>
 
 #include <google/protobuf/compiler/cpp/cpp_file.h>
@@ -102,7 +103,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
   // Generate header.
   {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      generator_context->Open(basename + ".h"));
+        generator_context->Open(basename + ".h"));
     io::Printer printer(output.get(), '$');
     file_generator.GenerateHeader(&printer);
   }
@@ -110,7 +111,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
   // Generate cc file.
   {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      generator_context->Open(basename + ".cc"));
+        generator_context->Open(basename + ".cc"));
     io::Printer printer(output.get(), '$');
     file_generator.GenerateSource(&printer);
   }

+ 88 - 32
src/google/protobuf/compiler/cpp/cpp_helpers.cc

@@ -82,6 +82,22 @@ hash_set<string> MakeKeywordsMap() {
 
 hash_set<string> kKeywords = MakeKeywordsMap();
 
+// Returns whether the provided descriptor has an extension. This includes its
+// nested types.
+bool HasExtension(const Descriptor* descriptor) {
+  if (descriptor->extension_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasExtension(descriptor->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
 string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
   string result;
   // Note:  I distrust ctype.h due to locales.
@@ -107,22 +123,6 @@ string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
   return result;
 }
 
-// Returns whether the provided descriptor has an extension. This includes its
-// nested types.
-bool HasExtension(const Descriptor* descriptor) {
-  if (descriptor->extension_count() > 0) {
-    return true;
-  }
-  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
-    if (HasExtension(descriptor->nested_type(i))) {
-      return true;
-    }
-  }
-  return false;
-}
-
-}  // namespace
-
 const char kThickSeparator[] =
   "// ===================================================================\n";
 const char kThinSeparator[] =
@@ -256,27 +256,35 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
   return "";
 }
 
+string Int32ToString(int number) {
+  // gcc rejects the decimal form of kint32min.
+  if (number == kint32min) {
+    GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
+    return "(~0x7fffffff)";
+  } else {
+    return SimpleItoa(number);
+  }
+}
+
+string Int64ToString(int64 number) {
+  // gcc rejects the decimal form of kint64min
+  if (number == kint64min) {
+    // Make sure we are in a 2's complement system.
+    GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(-0x8000000000000000),
+                   kint64min_value_error);
+    return "GOOGLE_LONGLONG(-0x8000000000000000)";
+  }
+  return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
+}
+
 string DefaultValue(const FieldDescriptor* field) {
   switch (field->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32:
-      // gcc rejects the decimal form of kint32min and kint64min.
-      if (field->default_value_int32() == kint32min) {
-        // Make sure we are in a 2's complement system.
-        GOOGLE_COMPILE_ASSERT(kint32min == -0x80000000, kint32min_value_error);
-        return "-0x80000000";
-      }
-      return SimpleItoa(field->default_value_int32());
+      return Int32ToString(field->default_value_int32());
     case FieldDescriptor::CPPTYPE_UINT32:
       return SimpleItoa(field->default_value_uint32()) + "u";
     case FieldDescriptor::CPPTYPE_INT64:
-      // See the comments for CPPTYPE_INT32.
-      if (field->default_value_int64() == kint64min) {
-        // Make sure we are in a 2's complement system.
-        GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(-0x8000000000000000),
-                       kint64min_value_error);
-        return "GOOGLE_LONGLONG(-0x8000000000000000)";
-      }
-      return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
+      return Int64ToString(field->default_value_int64());
     case FieldDescriptor::CPPTYPE_UINT64:
       return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
     case FieldDescriptor::CPPTYPE_DOUBLE: {
@@ -319,7 +327,7 @@ string DefaultValue(const FieldDescriptor* field) {
       return strings::Substitute(
           "static_cast< $0 >($1)",
           ClassName(field->enum_type(), true),
-          field->default_value_enum()->number());
+          Int32ToString(field->default_value_enum()->number()));
     case FieldDescriptor::CPPTYPE_STRING:
       return "\"" + EscapeTrigraphs(
         CEscape(field->default_value_string())) +
@@ -366,11 +374,39 @@ string GlobalShutdownFileName(const string& filename) {
   return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
 }
 
+// Return the qualified C++ name for a file level symbol.
+string QualifiedFileLevelSymbol(const string& package, const string& name) {
+  if (package.empty()) {
+    return StrCat("::", name);
+  }
+  return StrCat("::", DotsToColons(package), "::", name);
+}
+
 // Escape C++ trigraphs by escaping question marks to \?
 string EscapeTrigraphs(const string& to_escape) {
   return StringReplace(to_escape, "?", "\\?", true);
 }
 
+// Escaped function name to eliminate naming conflict.
+string SafeFunctionName(const Descriptor* descriptor,
+                        const FieldDescriptor* field,
+                        const string& prefix) {
+  // Do not use FieldName() since it will escape keywords.
+  string name = field->name();
+  LowerString(&name);
+  string function_name = prefix + name;
+  if (descriptor->FindFieldByName(function_name)) {
+    // Single underscore will also make it conflicting with the private data
+    // member. We use double underscore to escape function names.
+    function_name.append("__");
+  } else if (kKeywords.count(name) > 0) {
+    // If the field name is a keyword, we append the underscore back to keep it
+    // consistent with other function names.
+    function_name.append("_");
+  }
+  return function_name;
+}
+
 bool StaticInitializersForced(const FileDescriptor* file) {
   if (HasDescriptorMethods(file) || file->extension_count() > 0) {
     return true;
@@ -432,6 +468,26 @@ bool HasEnumDefinitions(const FileDescriptor* file) {
   return false;
 }
 
+bool IsStringOrMessage(const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_UINT64:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_BOOL:
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return false;
+    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return true;
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf

+ 22 - 2
src/google/protobuf/compiler/cpp/cpp_helpers.h

@@ -103,6 +103,12 @@ const char* PrimitiveTypeName(FieldDescriptor::CppType type);
 // methods of WireFormat.  For example, TYPE_INT32 becomes "Int32".
 const char* DeclaredTypeMethodName(FieldDescriptor::Type type);
 
+// Return the code that evaluates to the number when compiled.
+string Int32ToString(int number);
+
+// Return the code that evaluates to the number when compiled.
+string Int64ToString(int64 number);
+
 // Get code that evaluates to the field's default value.
 string DefaultValue(const FieldDescriptor* field);
 
@@ -115,14 +121,23 @@ string GlobalAddDescriptorsName(const string& filename);
 // Return the name of the AssignDescriptors() function for a given file.
 string GlobalAssignDescriptorsName(const string& filename);
 
+// Return the qualified C++ name for a file level symbol.
+string QualifiedFileLevelSymbol(const string& package, const string& name);
+
 // Return the name of the ShutdownFile() function for a given file.
 string GlobalShutdownFileName(const string& filename);
 
 // Escape C++ trigraphs by escaping question marks to \?
 string EscapeTrigraphs(const string& to_escape);
 
-// Do message classes in this file keep track of unknown fields?
-inline bool HasUnknownFields(const FileDescriptor* file) {
+// Escaped function name to eliminate naming conflict.
+string SafeFunctionName(const Descriptor* descriptor,
+                        const FieldDescriptor* field,
+                        const string& prefix);
+
+// Do message classes in this file use UnknownFieldSet?
+// Otherwise, messages will store unknown fields in a string
+inline bool UseUnknownFieldSet(const FileDescriptor* file) {
   return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
 }
 
@@ -178,6 +193,11 @@ void PrintHandlingOptionalStaticInitializers(
     const char* without_static_init);
 
 
+// Returns true if the field's CPPTYPE is string or message.
+bool IsStringOrMessage(const FieldDescriptor* field);
+
+string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf

File diff suppressed because it is too large
+ 599 - 112
src/google/protobuf/compiler/cpp/cpp_message.cc


+ 5 - 1
src/google/protobuf/compiler/cpp/cpp_message.h

@@ -35,8 +35,9 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
 
+#include <memory>
 #include <string>
-#include <google/protobuf/stubs/common.h>
+#include <vector>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 
@@ -132,6 +133,7 @@ class MessageGenerator {
 
   // Generate standard Message methods.
   void GenerateClear(io::Printer* printer);
+  void GenerateOneofClear(io::Printer* printer);
   void GenerateMergeFromCodedStream(io::Printer* printer);
   void GenerateSerializeWithCachedSizes(io::Printer* printer);
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
@@ -156,9 +158,11 @@ class MessageGenerator {
   string classname_;
   Options options_;
   FieldGeneratorMap field_generators_;
+  vector< vector<string> > runs_of_fields_;  // that might be trivially cleared
   scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
   scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
   scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+  bool uses_string_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
 };

+ 80 - 3
src/google/protobuf/compiler/cpp/cpp_message_field.cc

@@ -53,6 +53,12 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
       (HasFastArraySerialization(descriptor->message_type()->file()) ?
        "MaybeToArray" :
        "");
+  // NOTE: Escaped here to unblock proto1->proto2 migration.
+  // TODO(liujisi): Extend this to apply for other conflicting methods.
+  (*variables)["release_name"] =
+      SafeFunctionName(descriptor->containing_type(),
+                       descriptor, "release_");
+  (*variables)["full_name"] = descriptor->full_name();
 }
 
 }  // namespace
@@ -78,14 +84,15 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
     "inline const $type$& $name$() const$deprecation$;\n"
     "inline $type$* mutable_$name$()$deprecation$;\n"
-    "inline $type$* release_$name$()$deprecation$;\n"
+    "inline $type$* $release_name$()$deprecation$;\n"
     "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
 }
 
 void MessageFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline const $type$& $classname$::$name$() const {\n");
+    "inline const $type$& $classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n");
 
   PrintHandlingOptionalStaticInitializers(
     variables_, descriptor_->file(), printer,
@@ -99,9 +106,10 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "inline $type$* $classname$::mutable_$name$() {\n"
     "  set_has_$name$();\n"
     "  if ($name$_ == NULL) $name$_ = new $type$;\n"
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
-    "inline $type$* $classname$::release_$name$() {\n"
+    "inline $type$* $classname$::$release_name$() {\n"
     "  clear_has_$name$();\n"
     "  $type$* temp = $name$_;\n"
     "  $name$_ = NULL;\n"
@@ -115,6 +123,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "  } else {\n"
     "    clear_has_$name$();\n"
     "  }\n"
+    "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
     "}\n");
 }
 
@@ -178,6 +187,69 @@ GenerateByteSize(io::Printer* printer) const {
 
 // ===================================================================
 
+MessageOneofFieldGenerator::
+MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                           const Options& options)
+  : MessageFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
+
+void MessageOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+  printer->Print(variables_,
+    "inline const $type$& $classname$::$name$() const {\n"
+    "  return has_$name$() ? *$oneof_prefix$$name$_\n"
+    "                      : $type$::default_instance();\n"
+    "}\n"
+    "inline $type$* $classname$::mutable_$name$() {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "    $oneof_prefix$$name$_ = new $type$;\n"
+    "  }\n"
+    "  return $oneof_prefix$$name$_;\n"
+    "}\n"
+    "inline $type$* $classname$::$release_name$() {\n"
+    "  if (has_$name$()) {\n"
+    "    clear_has_$oneof_name$();\n"
+    "    $type$* temp = $oneof_prefix$$name$_;\n"
+    "    $oneof_prefix$$name$_ = NULL;\n"
+    "    return temp;\n"
+    "  } else {\n"
+    "    return NULL;\n"
+    "  }\n"
+    "}\n"
+    "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+    "  clear_$oneof_name$();\n"
+    "  if ($name$) {\n"
+    "    set_has_$name$();\n"
+    "    $oneof_prefix$$name$_ = $name$;\n"
+    "  }\n"
+    "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+  // if it is the active field, it cannot be NULL.
+  printer->Print(variables_,
+    "delete $oneof_prefix$$name$_;\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void MessageOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+  // Don't print any constructor code. The field is in a union. We allocate
+  // space only when this field is used.
+}
+
+// ===================================================================
+
 RepeatedMessageFieldGenerator::
 RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
                               const Options& options)
@@ -210,21 +282,26 @@ void RepeatedMessageFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline const $type$& $classname$::$name$(int index) const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.$cppget$(index);\n"
     "}\n"
     "inline $type$* $classname$::mutable_$name$(int index) {\n"
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_.Mutable(index);\n"
     "}\n"
     "inline $type$* $classname$::add_$name$() {\n"
+    "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  return $name$_.Add();\n"
     "}\n");
   printer->Print(variables_,
     "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
     "$classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
     "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "$classname$::mutable_$name$() {\n"
+    "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "}\n");
 }

+ 18 - 1
src/google/protobuf/compiler/cpp/cpp_message_field.h

@@ -63,13 +63,30 @@ class MessageFieldGenerator : public FieldGenerator {
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
- private:
+ protected:
   const FieldDescriptor* descriptor_;
   map<string, string> variables_;
 
+ private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
 };
 
+class MessageOneofFieldGenerator : public MessageFieldGenerator {
+ public:
+  explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                      const Options& options);
+  ~MessageOneofFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateClearingCode(io::Printer* printer) const;
+  void GenerateSwappingCode(io::Printer* printer) const;
+  void GenerateConstructorCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
 class RepeatedMessageFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,

+ 10 - 8
src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc

@@ -34,6 +34,8 @@
 //   It seemed like parameterizing it would add more complexity than it is
 //   worth.
 
+#include <memory>
+
 #include <google/protobuf/compiler/cpp/cpp_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -73,7 +75,7 @@ class TestGenerator : public CodeGenerator {
   void TryInsert(const string& filename, const string& insertion_point,
                  GeneratorContext* context) const {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      context->OpenForInsert(filename, insertion_point));
+        context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
   }
@@ -83,13 +85,13 @@ class TestGenerator : public CodeGenerator {
 // not verify that they are correctly-placed; that would require actually
 // compiling the output which is a bit more than I care to do for this test.
 TEST(CppPluginTest, PluginTest) {
-  File::WriteStringToFileOrDie(
-      "syntax = \"proto2\";\n"
-      "package foo;\n"
-      "message Bar {\n"
-      "  message Baz {}\n"
-      "}\n",
-      TestTempDir() + "/test.proto");
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
+                             "syntax = \"proto2\";\n"
+                             "package foo;\n"
+                             "message Bar {\n"
+                             "  message Baz {}\n"
+                             "}\n",
+                             true));
 
   google::protobuf::compiler::CommandLineInterface cli;
   cli.SetInputsAreProtoPathRelative(true);

+ 64 - 0
src/google/protobuf/compiler/cpp/cpp_primitive_field.cc

@@ -93,6 +93,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
   (*variables)["wire_format_field_type"] =
       "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
           static_cast<FieldDescriptorProto_Type>(descriptor->type()));
+  (*variables)["full_name"] = descriptor->full_name();
 }
 
 }  // namespace
@@ -124,11 +125,13 @@ void PrimitiveFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline $type$ $classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
     "inline void $classname$::set_$name$($type$ value) {\n"
     "  set_has_$name$();\n"
     "  $name$_ = value;\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
 }
 
@@ -191,6 +194,62 @@ GenerateByteSize(io::Printer* printer) const {
 
 // ===================================================================
 
+PrimitiveOneofFieldGenerator::
+PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options)
+  : PrimitiveFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
+
+void PrimitiveOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+  printer->Print(variables_,
+    "inline $type$ $classname$::$name$() const {\n"
+    "  if (has_$name$()) {\n"
+    "    return $oneof_prefix$$name$_;\n"
+    "  }\n"
+    "  return $default$;\n"
+    "}\n"
+    "inline void $classname$::set_$name$($type$ value) {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "  }\n"
+    "  $oneof_prefix$$name$_ = value;\n"
+    "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+  printer->Print(variables_,
+    "clear_$oneof_name$();\n"
+    "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
+    "         $type$, $wire_format_field_type$>(\n"
+    "       input, &$oneof_prefix$$name$_)));\n"
+    "set_has_$name$();\n");
+}
+
+// ===================================================================
+
 RepeatedPrimitiveFieldGenerator::
 RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
                                 const Options& options)
@@ -235,21 +294,26 @@ void RepeatedPrimitiveFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline $type$ $classname$::$name$(int index) const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.Get(index);\n"
     "}\n"
     "inline void $classname$::set_$name$(int index, $type$ value) {\n"
     "  $name$_.Set(index, value);\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
     "inline void $classname$::add_$name$($type$ value) {\n"
     "  $name$_.Add(value);\n"
+    "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n");
   printer->Print(variables_,
     "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
     "$classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
     "inline ::google::protobuf::RepeatedField< $type$ >*\n"
     "$classname$::mutable_$name$() {\n"
+    "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "}\n");
 }

+ 19 - 1
src/google/protobuf/compiler/cpp/cpp_primitive_field.h

@@ -63,13 +63,31 @@ class PrimitiveFieldGenerator : public FieldGenerator {
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
- private:
+ protected:
   const FieldDescriptor* descriptor_;
   map<string, string> variables_;
 
+ private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
 };
 
+class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+  explicit PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                        const Options& options);
+  ~PrimitiveOneofFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateClearingCode(io::Printer* printer) const;
+  void GenerateSwappingCode(io::Printer* printer) const;
+  void GenerateConstructorCode(io::Printer* printer) const;
+  void GenerateMergeFromCodedStream(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
 class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,

+ 0 - 1
src/google/protobuf/compiler/cpp/cpp_service.h

@@ -37,7 +37,6 @@
 
 #include <map>
 #include <string>
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.h>
 

+ 167 - 16
src/google/protobuf/compiler/cpp/cpp_string_field.cc

@@ -53,10 +53,16 @@ void SetStringVariables(const FieldDescriptor* descriptor,
   (*variables)["default_length"] =
       SimpleItoa(descriptor->default_value_string().length());
   (*variables)["default_variable"] = descriptor->default_value_string().empty()
-      ? "&::google::protobuf::internal::GetEmptyString()"
+      ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()"
       : "_default_" + FieldName(descriptor) + "_";
   (*variables)["pointer_type"] =
       descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
+  // NOTE: Escaped here to unblock proto1->proto2 migration.
+  // TODO(liujisi): Extend this to apply for other conflicting methods.
+  (*variables)["release_name"] =
+      SafeFunctionName(descriptor->containing_type(),
+                       descriptor, "release_");
+  (*variables)["full_name"] = descriptor->full_name();
 }
 
 }  // namespace
@@ -75,6 +81,10 @@ StringFieldGenerator::~StringFieldGenerator() {}
 void StringFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_, "::std::string* $name$_;\n");
+}
+
+void StringFieldGenerator::
+GenerateStaticMembers(io::Printer* printer) const {
   if (!descriptor_->default_value_string().empty()) {
     printer->Print(variables_, "static ::std::string* $default_variable$;\n");
   }
@@ -113,7 +123,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
     "inline void set_$name$(const $pointer_type$* value, size_t size)"
                  "$deprecation$;\n"
     "inline ::std::string* mutable_$name$()$deprecation$;\n"
-    "inline ::std::string* release_$name$()$deprecation$;\n"
+    "inline ::std::string* $release_name$()$deprecation$;\n"
     "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
 
 
@@ -128,6 +138,7 @@ void StringFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline const ::std::string& $classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return *$name$_;\n"
     "}\n"
     "inline void $classname$::set_$name$(const ::std::string& value) {\n"
@@ -136,6 +147,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(value);\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
     "inline void $classname$::set_$name$(const char* value) {\n"
     "  set_has_$name$();\n"
@@ -143,6 +155,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(value);\n"
+    "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
     "}\n"
     "inline "
     "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
@@ -151,6 +164,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
+    "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
     "}\n"
     "inline ::std::string* $classname$::mutable_$name$() {\n"
     "  set_has_$name$();\n"
@@ -164,9 +178,10 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   }
   printer->Print(variables_,
     "  }\n"
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
-    "inline ::std::string* $classname$::release_$name$() {\n"
+    "inline ::std::string* $classname$::$release_name$() {\n"
     "  clear_has_$name$();\n"
     "  if ($name$_ == $default_variable$) {\n"
     "    return NULL;\n"
@@ -187,6 +202,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    clear_has_$name$();\n"
     "    $name$_ = const_cast< ::std::string*>($default_variable$);\n"
     "  }\n"
+    "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
     "}\n");
 }
 
@@ -263,9 +279,10 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (HasUtf8Verification(descriptor_->file()) &&
       descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
       "  this->$name$().data(), this->$name$().length(),\n"
-      "  ::google::protobuf::internal::WireFormat::PARSE);\n");
+      "  ::google::protobuf::internal::WireFormat::PARSE,\n"
+      "  \"$name$\");\n");
   }
 }
 
@@ -274,12 +291,13 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   if (HasUtf8Verification(descriptor_->file()) &&
       descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
       "  this->$name$().data(), this->$name$().length(),\n"
-      "  ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+      "  ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+      "  \"$name$\");\n");
   }
   printer->Print(variables_,
-    "::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
+    "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n"
     "  $number$, this->$name$(), output);\n");
 }
 
@@ -288,9 +306,10 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   if (HasUtf8Verification(descriptor_->file()) &&
       descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
       "  this->$name$().data(), this->$name$().length(),\n"
-      "  ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+      "  ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+      "  \"$name$\");\n");
   }
   printer->Print(variables_,
     "target =\n"
@@ -308,6 +327,125 @@ GenerateByteSize(io::Printer* printer) const {
 
 // ===================================================================
 
+StringOneofFieldGenerator::
+StringOneofFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options)
+  : StringFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
+
+void StringOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+  printer->Print(variables_,
+    "inline const ::std::string& $classname$::$name$() const {\n"
+    "  if (has_$name$()) {\n"
+    "    return *$oneof_prefix$$name$_;\n"
+    "  }\n");
+  if (descriptor_->default_value_string().empty()) {
+    printer->Print(variables_,
+      "  return ::google::protobuf::internal::GetEmptyStringAlreadyInited();\n");
+  } else {
+    printer->Print(variables_,
+      "  return *$default_variable$;\n");
+  }
+  printer->Print(variables_,
+    "}\n"
+    "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "    $oneof_prefix$$name$_ = new ::std::string;\n"
+    "  }\n"
+    "  $oneof_prefix$$name$_->assign(value);\n"
+    "}\n"
+    "inline void $classname$::set_$name$(const char* value) {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "    $oneof_prefix$$name$_ = new ::std::string;\n"
+    "  }\n"
+    "  $oneof_prefix$$name$_->assign(value);\n"
+    "}\n"
+    "inline "
+    "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "    $oneof_prefix$$name$_ = new ::std::string;\n"
+    "  }\n"
+    "  $oneof_prefix$$name$_->assign(\n"
+    "      reinterpret_cast<const char*>(value), size);\n"
+    "}\n"
+    "inline ::std::string* $classname$::mutable_$name$() {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n");
+  if (descriptor_->default_value_string().empty()) {
+    printer->Print(variables_,
+      "    $oneof_prefix$$name$_ = new ::std::string;\n");
+  } else {
+    printer->Print(variables_,
+      "    $oneof_prefix$$name$_ = new ::std::string(*$default_variable$);\n");
+  }
+  printer->Print(variables_,
+    "  }\n"
+    "  return $oneof_prefix$$name$_;\n"
+    "}\n"
+    "inline ::std::string* $classname$::$release_name$() {\n"
+    "  if (has_$name$()) {\n"
+    "    clear_has_$oneof_name$();\n"
+    "    ::std::string* temp = $oneof_prefix$$name$_;\n"
+    "    $oneof_prefix$$name$_ = NULL;\n"
+    "    return temp;\n"
+    "  } else {\n"
+    "    return NULL;\n"
+    "  }\n"
+    "}\n"
+    "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+    "  clear_$oneof_name$();\n"
+    "  if ($name$) {\n"
+    "    set_has_$name$();\n"
+    "    $oneof_prefix$$name$_ = $name$;\n"
+    "  }\n"
+    "}\n");
+}
+
+void StringOneofFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+    printer->Print(variables_,
+      "delete $oneof_prefix$$name$_;\n");
+}
+
+void StringOneofFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void StringOneofFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+  if (!descriptor_->default_value_string().empty()) {
+    printer->Print(variables_,
+      "  $classname$_default_oneof_instance_->$name$_ = "
+      "$classname$::$default_variable$;\n");
+  } else {
+    printer->Print(variables_,
+      "  $classname$_default_oneof_instance_->$name$_ = "
+      "$default_variable$;\n");
+  }
+}
+
+void StringOneofFieldGenerator::
+GenerateDestructorCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has_$name$()) {\n"
+    "  delete $oneof_prefix$$name$_;\n"
+    "}\n");
+}
+
+// ===================================================================
+
 RepeatedStringFieldGenerator::
 RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
                              const Options& options)
@@ -365,43 +503,53 @@ void RepeatedStringFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
   printer->Print(variables_,
     "inline const ::std::string& $classname$::$name$(int index) const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.$cppget$(index);\n"
     "}\n"
     "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_.Mutable(index);\n"
     "}\n"
     "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "}\n"
     "inline void $classname$::set_$name$(int index, const char* value) {\n"
     "  $name$_.Mutable(index)->assign(value);\n"
+    "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
     "}\n"
     "inline void "
     "$classname$::set_$name$"
     "(int index, const $pointer_type$* value, size_t size) {\n"
     "  $name$_.Mutable(index)->assign(\n"
     "    reinterpret_cast<const char*>(value), size);\n"
+    "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
     "}\n"
     "inline ::std::string* $classname$::add_$name$() {\n"
     "  return $name$_.Add();\n"
     "}\n"
     "inline void $classname$::add_$name$(const ::std::string& value) {\n"
     "  $name$_.Add()->assign(value);\n"
+    "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n"
     "inline void $classname$::add_$name$(const char* value) {\n"
     "  $name$_.Add()->assign(value);\n"
+    "  // @@protoc_insertion_point(field_add_char:$full_name$)\n"
     "}\n"
     "inline void "
     "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
     "  $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
+    "  // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
     "}\n");
   printer->Print(variables_,
     "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
     "$classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
     "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
     "$classname$::mutable_$name$() {\n"
+    "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "}\n");
 }
@@ -434,10 +582,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (HasUtf8Verification(descriptor_->file()) &&
       descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
       "  this->$name$(this->$name$_size() - 1).data(),\n"
       "  this->$name$(this->$name$_size() - 1).length(),\n"
-      "  ::google::protobuf::internal::WireFormat::PARSE);\n");
+      "  ::google::protobuf::internal::WireFormat::PARSE,\n"
+      "  \"$name$\");\n");
   }
 }
 
@@ -448,9 +597,10 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   if (HasUtf8Verification(descriptor_->file()) &&
       descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
       "  this->$name$(i).data(), this->$name$(i).length(),\n"
-      "  ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+      "  ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+      "  \"$name$\");\n");
   }
   printer->Print(variables_,
     "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
@@ -465,9 +615,10 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   if (HasUtf8Verification(descriptor_->file()) &&
       descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     printer->Print(variables_,
-      "  ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
+      "  ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
       "    this->$name$(i).data(), this->$name$(i).length(),\n"
-      "    ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
+      "    ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
+      "    \"$name$\");\n");
   }
   printer->Print(variables_,
     "  target = ::google::protobuf::internal::WireFormatLite::\n"

+ 20 - 1
src/google/protobuf/compiler/cpp/cpp_string_field.h

@@ -52,6 +52,7 @@ class StringFieldGenerator : public FieldGenerator {
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateStaticMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
@@ -67,13 +68,31 @@ class StringFieldGenerator : public FieldGenerator {
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
- private:
+ protected:
   const FieldDescriptor* descriptor_;
   map<string, string> variables_;
 
+ private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
 };
 
+class StringOneofFieldGenerator : public StringFieldGenerator {
+ public:
+  explicit StringOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                     const Options& options);
+  ~StringOneofFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateClearingCode(io::Printer* printer) const;
+  void GenerateSwappingCode(io::Printer* printer) const;
+  void GenerateConstructorCode(io::Printer* printer) const;
+  void GenerateDestructorCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
+};
+
 class RepeatedStringFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,

+ 9 - 0
src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto

@@ -98,6 +98,7 @@ message TestConflictingSymbolNames {
   // Some keywords.
   optional uint32 int = 30;
   optional uint32 friend = 31;
+  optional uint32 class = 37;
 
   // The generator used to #define a macro called "DO" inside the .cc file.
   message DO {}
@@ -107,6 +108,14 @@ message TestConflictingSymbolNames {
   optional int32 field_type = 33;
   optional bool is_packed = 34;
 
+  // test conflicting release_$name$. "length" and "do" field in this message
+  // must remain string or message fields to make the test valid.
+  optional string release_length = 35;
+  // A more extreme case, the field name "do" here is a keyword, which will be
+  // escaped to "do_" already. Test there is no conflict even with escaped field
+  // names.
+  optional DO release_do = 36;
+
   extensions 1000 to max;
 }
 

+ 726 - 6
src/google/protobuf/compiler/cpp/cpp_unittest.cc

@@ -46,6 +46,7 @@
 
 #include <google/protobuf/compiler/cpp/cpp_unittest.h>
 
+#include <memory>
 #include <vector>
 
 #include <google/protobuf/unittest.pb.h>
@@ -53,6 +54,7 @@
 #include <google/protobuf/unittest_embed_optimize_for.pb.h>
 #include <google/protobuf/unittest_no_generic_services.pb.h>
 #include <google/protobuf/test_util.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h>
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/io/coded_stream.h>
@@ -148,6 +150,19 @@ TEST(GeneratedMessageTest, Defaults) {
             &message.optional_import_message());
 }
 
+TEST(GeneratedMessageTest, Int32StringConversion) {
+  EXPECT_EQ("971", Int32ToString(971));
+  EXPECT_EQ("(~0x7fffffff)", Int32ToString(kint32min));
+  EXPECT_EQ("2147483647", Int32ToString(kint32max));
+}
+
+TEST(GeneratedMessageTest, Int64StringConversion) {
+  EXPECT_EQ("GOOGLE_LONGLONG(971)", Int64ToString(971));
+  EXPECT_EQ("GOOGLE_LONGLONG(-2147483648)", Int64ToString(kint32min));
+  EXPECT_EQ("GOOGLE_LONGLONG(-0x8000000000000000)", Int64ToString(kint64min));
+  EXPECT_EQ("GOOGLE_LONGLONG(9223372036854775807)", Int64ToString(kint64max));
+}
+
 TEST(GeneratedMessageTest, FloatingPointDefaults) {
   const unittest::TestExtremeDefaultValues& extreme_default =
       unittest::TestExtremeDefaultValues::default_instance();
@@ -233,11 +248,10 @@ TEST(GeneratedMessageTest, ReleaseString) {
 
   message.set_default_string("blah");
   EXPECT_TRUE(message.has_default_string());
-  string* str = message.release_default_string();
+  scoped_ptr<string> str(message.release_default_string());
   EXPECT_FALSE(message.has_default_string());
   ASSERT_TRUE(str != NULL);
   EXPECT_EQ("blah", *str);
-  delete str;
 
   EXPECT_EQ(NULL, message.release_default_string());
   EXPECT_FALSE(message.has_default_string());
@@ -253,12 +267,11 @@ TEST(GeneratedMessageTest, ReleaseMessage) {
   EXPECT_FALSE(message.has_optional_nested_message());
 
   message.mutable_optional_nested_message()->set_bb(1);
-  unittest::TestAllTypes::NestedMessage* nest =
-      message.release_optional_nested_message();
+  scoped_ptr<unittest::TestAllTypes::NestedMessage> nest(
+      message.release_optional_nested_message());
   EXPECT_FALSE(message.has_optional_nested_message());
   ASSERT_TRUE(nest != NULL);
   EXPECT_EQ(1, nest->bb());
-  delete nest;
 
   EXPECT_EQ(NULL, message.release_optional_nested_message());
   EXPECT_FALSE(message.has_optional_nested_message());
@@ -381,6 +394,7 @@ TEST(GeneratedMessageTest, StringCharStarLength) {
   EXPECT_EQ("wx", message.repeated_string(0));
 }
 
+
 TEST(GeneratedMessageTest, CopyFrom) {
   unittest::TestAllTypes message1, message2;
 
@@ -393,6 +407,7 @@ TEST(GeneratedMessageTest, CopyFrom) {
   TestUtil::ExpectAllFieldsSet(message2);
 }
 
+
 TEST(GeneratedMessageTest, SwapWithEmpty) {
   unittest::TestAllTypes message1, message2;
   TestUtil::SetAllFields(&message1);
@@ -763,6 +778,9 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) {
   message.set_friend_(5);
   EXPECT_EQ(5, message.friend_());
 
+  message.set_class_(6);
+  EXPECT_EQ(6, message.class_());
+
   // Instantiate extension template functions to test conflicting template
   // parameter names.
   typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage;
@@ -840,6 +858,40 @@ TEST(GeneratedMessageTest, TestSpaceUsed) {
             message1.SpaceUsed());
 }
 
+TEST(GeneratedMessageTest, TestOneofSpaceUsed) {
+  unittest::TestOneof2 message1;
+  EXPECT_LE(sizeof(unittest::TestOneof2), message1.SpaceUsed());
+
+  const int empty_message_size = message1.SpaceUsed();
+  // Setting primitive types shouldn't affect the space used.
+  message1.set_foo_int(123);
+  message1.set_bar_int(12345);
+  EXPECT_EQ(empty_message_size, message1.SpaceUsed());
+
+  // Setting a string in oneof to a small value should only increase SpaceUsed()
+  // by the size of a string object.
+  message1.set_foo_string("abc");
+  EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed());
+
+  // Setting a string in oneof to a value larger than the string object itself
+  // should increase SpaceUsed(), because it cannot store the value internally.
+  message1.set_foo_string(string(sizeof(string) + 1, 'x'));
+  int min_expected_increase = message1.foo_string().capacity() +
+      sizeof(string);
+  EXPECT_LE(empty_message_size + min_expected_increase,
+            message1.SpaceUsed());
+
+  // Setting a message in oneof should delete the other fields and increase the
+  // size by the size of the nested message type. NestedMessage is simple enough
+  // that it is equal to sizeof(NestedMessage)
+  message1.mutable_foo_message();
+  ASSERT_EQ(sizeof(unittest::TestOneof2::NestedMessage),
+            message1.foo_message().SpaceUsed());
+  EXPECT_EQ(empty_message_size +
+            sizeof(unittest::TestOneof2::NestedMessage),
+            message1.SpaceUsed());
+}
+
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
 
 
@@ -887,6 +939,9 @@ TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
     case unittest::TestAllTypes::BAZ:
       i = 3;
       break;
+    case unittest::TestAllTypes::NEG:
+      i = -1;
+      break;
     // no default case:  We want to make sure the compiler recognizes that
     //   all cases are covered.  (GCC warns if you do not cover all cases of
     //   an enum in a switch.)
@@ -915,7 +970,7 @@ TEST(GeneratedEnumTest, IsValidValue) {
 }
 
 TEST(GeneratedEnumTest, MinAndMax) {
-  EXPECT_EQ(unittest::TestAllTypes::FOO,
+  EXPECT_EQ(unittest::TestAllTypes::NEG,
             unittest::TestAllTypes::NestedEnum_MIN);
   EXPECT_EQ(unittest::TestAllTypes::BAZ,
             unittest::TestAllTypes::NestedEnum_MAX);
@@ -989,6 +1044,20 @@ TEST(GeneratedEnumTest, GetEnumDescriptor) {
             GetEnumDescriptor<unittest::TestSparseEnum>());
 }
 
+enum NonProtoEnum {
+  kFoo = 1,
+};
+
+TEST(GeneratedEnumTest, IsProtoEnumTypeTrait) {
+  EXPECT_TRUE(is_proto_enum<unittest::TestAllTypes::NestedEnum>::value);
+  EXPECT_TRUE(is_proto_enum<unittest::ForeignEnum>::value);
+  EXPECT_TRUE(is_proto_enum<unittest::TestEnumWithDupValue>::value);
+  EXPECT_TRUE(is_proto_enum<unittest::TestSparseEnum>::value);
+
+  EXPECT_FALSE(is_proto_enum<int>::value);
+  EXPECT_FALSE(is_proto_enum<NonProtoEnum>::value);
+}
+
 #endif  // PROTOBUF_TEST_NO_DESCRIPTORS
 
 // ===================================================================
@@ -1288,6 +1357,657 @@ TEST_F(GeneratedServiceTest, NotImplemented) {
   EXPECT_TRUE(controller.called_);
 }
 
+// ===================================================================
+
+class OneofTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+  }
+
+  void ExpectEnumCasesWork(const unittest::TestOneof2 &message) {
+    switch (message.foo_case()) {
+      case unittest::TestOneof2::kFooInt:
+        EXPECT_TRUE(message.has_foo_int());
+        break;
+      case unittest::TestOneof2::kFooString:
+        EXPECT_TRUE(message.has_foo_string());
+        break;
+      case unittest::TestOneof2::kFooBytes:
+        EXPECT_TRUE(message.has_foo_bytes());
+        break;
+      case unittest::TestOneof2::kFooEnum:
+        EXPECT_TRUE(message.has_foo_enum());
+        break;
+      case unittest::TestOneof2::kFooMessage:
+        EXPECT_TRUE(message.has_foo_message());
+        break;
+      case unittest::TestOneof2::kFoogroup:
+        EXPECT_TRUE(message.has_foogroup());
+        break;
+      case unittest::TestOneof2::FOO_NOT_SET:
+        break;
+    }
+  }
+};
+
+TEST_F(OneofTest, SettingOneFieldClearsOthers) {
+  unittest::TestOneof2 message;
+
+  message.set_foo_int(123);
+  EXPECT_TRUE(message.has_foo_int());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.set_foo_string("foo");
+  EXPECT_TRUE(message.has_foo_string());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+
+  message.set_foo_bytes("qux");
+  EXPECT_TRUE(message.has_foo_bytes());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.set_foo_enum(unittest::TestOneof2::FOO);
+  EXPECT_TRUE(message.has_foo_enum());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.mutable_foo_message()->set_qux_int(234);
+  EXPECT_TRUE(message.has_foo_message());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.mutable_foogroup()->set_a(345);
+  EXPECT_TRUE(message.has_foogroup());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+
+  // we repeat this because we didn't test if this properly clears other fields
+  // at the beginning.
+  message.set_foo_int(123);
+  EXPECT_TRUE(message.has_foo_int());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+}
+
+TEST_F(OneofTest, EnumCases) {
+  unittest::TestOneof2 message;
+
+  message.set_foo_int(123);
+  ExpectEnumCasesWork(message);
+  message.set_foo_string("foo");
+  ExpectEnumCasesWork(message);
+  message.set_foo_bytes("qux");
+  ExpectEnumCasesWork(message);
+  message.set_foo_enum(unittest::TestOneof2::FOO);
+  ExpectEnumCasesWork(message);
+  message.mutable_foo_message()->set_qux_int(234);
+  ExpectEnumCasesWork(message);
+  message.mutable_foogroup()->set_a(345);
+  ExpectEnumCasesWork(message);
+}
+
+TEST_F(OneofTest, PrimitiveType) {
+  unittest::TestOneof2 message;
+  // Unset field returns default value
+  EXPECT_EQ(message.foo_int(), 0);
+
+  message.set_foo_int(123);
+  EXPECT_TRUE(message.has_foo_int());
+  EXPECT_EQ(message.foo_int(), 123);
+  message.clear_foo_int();
+  EXPECT_FALSE(message.has_foo_int());
+}
+
+TEST_F(OneofTest, EnumType) {
+  unittest::TestOneof2 message;
+  // Unset field returns default value
+  EXPECT_EQ(message.foo_enum(), 1);
+
+  message.set_foo_enum(unittest::TestOneof2::FOO);
+  EXPECT_TRUE(message.has_foo_enum());
+  EXPECT_EQ(message.foo_enum(), unittest::TestOneof2::FOO);
+  message.clear_foo_enum();
+  EXPECT_FALSE(message.has_foo_enum());
+}
+
+TEST_F(OneofTest, SetString) {
+  // Check that setting a string field in various ways works
+  unittest::TestOneof2 message;
+
+  // Unset field returns default value
+  EXPECT_EQ(message.foo_string(), "");
+
+  message.set_foo_string("foo");
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "foo");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.set_foo_string(string("bar"));
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "bar");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+
+  message.set_foo_string("qux", 3);
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "qux");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.mutable_foo_string()->assign("quux");
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "quux");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.set_foo_string("corge");
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "corge");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+}
+
+TEST_F(OneofTest, ReleaseString) {
+  // Check that release_foo() starts out NULL, and gives us a value
+  // that we can delete after it's been set.
+  unittest::TestOneof2 message;
+
+  EXPECT_EQ(NULL, message.release_foo_string());
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.set_foo_string("blah");
+  EXPECT_TRUE(message.has_foo_string());
+  scoped_ptr<string> str(message.release_foo_string());
+  EXPECT_FALSE(message.has_foo_string());
+  ASSERT_TRUE(str != NULL);
+  EXPECT_EQ("blah", *str);
+
+  EXPECT_EQ(NULL, message.release_foo_string());
+  EXPECT_FALSE(message.has_foo_string());
+}
+
+TEST_F(OneofTest, SetAllocatedString) {
+  // Check that set_allocated_foo() works for strings.
+  unittest::TestOneof2 message;
+
+  EXPECT_FALSE(message.has_foo_string());
+  const string kHello("hello");
+  message.set_foo_string(kHello);
+  EXPECT_TRUE(message.has_foo_string());
+
+  message.set_allocated_foo_string(NULL);
+  EXPECT_FALSE(message.has_foo_string());
+  EXPECT_EQ("", message.foo_string());
+
+  message.set_allocated_foo_string(new string(kHello));
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(kHello, message.foo_string());
+}
+
+
+TEST_F(OneofTest, SetMessage) {
+  // Check that setting a message field works
+  unittest::TestOneof2 message;
+
+  // Unset field returns default instance
+  EXPECT_EQ(&message.foo_message(),
+            &unittest::TestOneof2_NestedMessage::default_instance());
+  EXPECT_EQ(message.foo_message().qux_int(), 0);
+
+  message.mutable_foo_message()->set_qux_int(234);
+  EXPECT_TRUE(message.has_foo_message());
+  EXPECT_EQ(message.foo_message().qux_int(), 234);
+  message.clear_foo_message();
+  EXPECT_FALSE(message.has_foo_message());
+}
+
+TEST_F(OneofTest, ReleaseMessage) {
+  // Check that release_foo() starts out NULL, and gives us a value
+  // that we can delete after it's been set.
+  unittest::TestOneof2 message;
+
+  EXPECT_EQ(NULL, message.release_foo_message());
+  EXPECT_FALSE(message.has_foo_message());
+
+  message.mutable_foo_message()->set_qux_int(1);
+  EXPECT_TRUE(message.has_foo_message());
+  scoped_ptr<unittest::TestOneof2_NestedMessage> mes(
+      message.release_foo_message());
+  EXPECT_FALSE(message.has_foo_message());
+  ASSERT_TRUE(mes != NULL);
+  EXPECT_EQ(1, mes->qux_int());
+
+  EXPECT_EQ(NULL, message.release_foo_message());
+  EXPECT_FALSE(message.has_foo_message());
+}
+
+TEST_F(OneofTest, SetAllocatedMessage) {
+  // Check that set_allocated_foo() works for messages.
+  unittest::TestOneof2 message;
+
+  EXPECT_FALSE(message.has_foo_message());
+
+  message.mutable_foo_message()->set_qux_int(1);
+  EXPECT_TRUE(message.has_foo_message());
+
+  message.set_allocated_foo_message(NULL);
+  EXPECT_FALSE(message.has_foo_message());
+  EXPECT_EQ(&message.foo_message(),
+            &unittest::TestOneof2_NestedMessage::default_instance());
+
+  message.mutable_foo_message()->set_qux_int(1);
+  unittest::TestOneof2_NestedMessage* mes = message.release_foo_message();
+  ASSERT_TRUE(mes != NULL);
+  EXPECT_FALSE(message.has_foo_message());
+
+  message.set_allocated_foo_message(mes);
+  EXPECT_TRUE(message.has_foo_message());
+  EXPECT_EQ(1, message.foo_message().qux_int());
+}
+
+
+TEST_F(OneofTest, Clear) {
+  unittest::TestOneof2 message;
+
+  message.set_foo_int(1);
+  EXPECT_TRUE(message.has_foo_int());
+  message.clear_foo_int();
+  EXPECT_FALSE(message.has_foo_int());
+}
+
+TEST_F(OneofTest, Defaults) {
+  unittest::TestOneof2 message;
+
+  EXPECT_FALSE(message.has_foo_int());
+  EXPECT_EQ(message.foo_int(), 0);
+
+  EXPECT_FALSE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "");
+
+
+  EXPECT_FALSE(message.has_foo_bytes());
+  EXPECT_EQ(message.foo_bytes(), "");
+
+  EXPECT_FALSE(message.has_foo_enum());
+  EXPECT_EQ(message.foo_enum(), 1);
+
+  EXPECT_FALSE(message.has_foo_message());
+  EXPECT_EQ(message.foo_message().qux_int(), 0);
+
+  EXPECT_FALSE(message.has_foogroup());
+  EXPECT_EQ(message.foogroup().a(), 0);
+
+
+  EXPECT_FALSE(message.has_bar_int());
+  EXPECT_EQ(message.bar_int(), 5);
+
+  EXPECT_FALSE(message.has_bar_string());
+  EXPECT_EQ(message.bar_string(), "STRING");
+
+
+  EXPECT_FALSE(message.has_bar_bytes());
+  EXPECT_EQ(message.bar_bytes(), "BYTES");
+
+  EXPECT_FALSE(message.has_bar_enum());
+  EXPECT_EQ(message.bar_enum(), 2);
+}
+
+TEST_F(OneofTest, SwapWithEmpty) {
+  unittest::TestOneof2 message1, message2;
+  message1.set_foo_string("FOO");
+  EXPECT_TRUE(message1.has_foo_string());
+  message1.Swap(&message2);
+  EXPECT_FALSE(message1.has_foo_string());
+  EXPECT_TRUE(message2.has_foo_string());
+  EXPECT_EQ(message2.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, SwapWithSelf) {
+  unittest::TestOneof2 message;
+  message.set_foo_string("FOO");
+  EXPECT_TRUE(message.has_foo_string());
+  message.Swap(&message);
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, SwapBothHasFields) {
+  unittest::TestOneof2 message1, message2;
+
+  message1.set_foo_string("FOO");
+  EXPECT_TRUE(message1.has_foo_string());
+  message2.mutable_foo_message()->set_qux_int(1);
+  EXPECT_TRUE(message2.has_foo_message());
+
+  message1.Swap(&message2);
+  EXPECT_FALSE(message1.has_foo_string());
+  EXPECT_FALSE(message2.has_foo_message());
+  EXPECT_TRUE(message1.has_foo_message());
+  EXPECT_EQ(message1.foo_message().qux_int(), 1);
+  EXPECT_TRUE(message2.has_foo_string());
+  EXPECT_EQ(message2.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, CopyContructor) {
+  unittest::TestOneof2 message1;
+  message1.set_foo_bytes("FOO");
+
+  unittest::TestOneof2 message2(message1);
+  EXPECT_TRUE(message2.has_foo_bytes());
+  EXPECT_EQ(message2.foo_bytes(), "FOO");
+}
+
+TEST_F(OneofTest, CopyFrom) {
+  unittest::TestOneof2 message1, message2;
+  message1.set_foo_enum(unittest::TestOneof2::BAR);
+  EXPECT_TRUE(message1.has_foo_enum());
+
+  message2.CopyFrom(message1);
+  EXPECT_TRUE(message2.has_foo_enum());
+  EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::BAR);
+
+  // Copying from self should be a no-op.
+  message2.CopyFrom(message2);
+  EXPECT_TRUE(message2.has_foo_enum());
+  EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::BAR);
+}
+
+TEST_F(OneofTest, CopyAssignmentOperator) {
+  unittest::TestOneof2 message1;
+  message1.mutable_foo_message()->set_qux_int(123);
+  EXPECT_TRUE(message1.has_foo_message());
+
+  unittest::TestOneof2 message2;
+  message2 = message1;
+  EXPECT_EQ(message2.foo_message().qux_int(), 123);
+
+  // Make sure that self-assignment does something sane.
+  message2 = message2;
+  EXPECT_EQ(message2.foo_message().qux_int(), 123);
+}
+
+TEST_F(OneofTest, UpcastCopyFrom) {
+  // Test the CopyFrom method that takes in the generic const Message&
+  // parameter.
+  unittest::TestOneof2 message1, message2;
+  message1.mutable_foogroup()->set_a(123);
+  EXPECT_TRUE(message1.has_foogroup());
+
+  const Message* source = implicit_cast<const Message*>(&message1);
+  message2.CopyFrom(*source);
+
+  EXPECT_TRUE(message2.has_foogroup());
+  EXPECT_EQ(message2.foogroup().a(), 123);
+}
+
+// Test the generated SerializeWithCachedSizesToArray(),
+// This indirectly tests MergePartialFromCodedStream()
+// We have to test each field type separately because we cannot set them at the
+// same time
+TEST_F(OneofTest, SerializationToArray) {
+  // Primitive type
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_int(123);
+    int size = message1.ByteSize();
+    data.resize(size);
+    uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+    uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_int(), 123);
+  }
+
+  // String
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_string("foo");
+    int size = message1.ByteSize();
+    data.resize(size);
+    uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+    uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_string(), "foo");
+  }
+
+
+  // Bytes
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_bytes("qux");
+    int size = message1.ByteSize();
+    data.resize(size);
+    uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+    uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_bytes(), "qux");
+  }
+
+  // Enum
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_enum(unittest::TestOneof2::FOO);
+    int size = message1.ByteSize();
+    data.resize(size);
+    uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+    uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO);
+  }
+
+  // Message
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.mutable_foo_message()->set_qux_int(234);
+    int size = message1.ByteSize();
+    data.resize(size);
+    uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+    uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_message().qux_int(), 234);
+  }
+
+  // Group
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.mutable_foogroup()->set_a(345);
+    int size = message1.ByteSize();
+    data.resize(size);
+    uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+    uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foogroup().a(), 345);
+  }
+
+}
+
+// Test the generated SerializeWithCachedSizes() by forcing the buffer to write
+// one byte at a time.
+// This indirectly tests MergePartialFromCodedStream()
+// We have to test each field type separately because we cannot set them at the
+// same time
+TEST_F(OneofTest, SerializationToStream) {
+  // Primitive type
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_int(123);
+    int size = message1.ByteSize();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_int(), 123);
+  }
+
+  // String
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_string("foo");
+    int size = message1.ByteSize();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_string(), "foo");
+  }
+
+
+  // Bytes
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_bytes("qux");
+    int size = message1.ByteSize();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_bytes(), "qux");
+  }
+
+  // Enum
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.set_foo_enum(unittest::TestOneof2::FOO);
+    int size = message1.ByteSize();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO);
+  }
+
+  // Message
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.mutable_foo_message()->set_qux_int(234);
+    int size = message1.ByteSize();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_message().qux_int(), 234);
+  }
+
+  // Group
+  {
+    unittest::TestOneof2 message1, message2;
+    string data;
+    message1.mutable_foogroup()->set_a(345);
+    int size = message1.ByteSize();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foogroup().a(), 345);
+  }
+
+}
+
+TEST_F(OneofTest, MergeFrom) {
+  unittest::TestOneof2 message1, message2;
+
+  message1.set_foo_int(123);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_int());
+  EXPECT_EQ(message2.foo_int(), 123);
+
+  message1.set_foo_string("foo");
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_string());
+  EXPECT_EQ(message2.foo_string(), "foo");
+
+
+  message1.set_foo_bytes("qux");
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_bytes());
+  EXPECT_EQ(message2.foo_bytes(), "qux");
+
+  message1.set_foo_enum(unittest::TestOneof2::FOO);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_enum());
+  EXPECT_EQ(message2.foo_enum(), unittest::TestOneof2::FOO);
+
+  message1.mutable_foo_message()->set_qux_int(234);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_message());
+  EXPECT_EQ(message2.foo_message().qux_int(), 234);
+
+  message1.mutable_foogroup()->set_a(345);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foogroup());
+  EXPECT_EQ(message2.foogroup().a(), 345);
+
+}
+
 }  // namespace cpp_unittest
 }  // namespace cpp
 }  // namespace compiler

+ 30 - 9
src/google/protobuf/compiler/importer.cc

@@ -43,6 +43,7 @@
 #include <errno.h>
 
 #include <algorithm>
+#include <memory>
 
 #include <google/protobuf/compiler/importer.h>
 
@@ -124,7 +125,8 @@ bool SourceTreeDescriptorDatabase::FindFileByName(
   scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
   if (input == NULL) {
     if (error_collector_ != NULL) {
-      error_collector_->AddError(filename, -1, 0, "File not found.");
+      error_collector_->AddError(filename, -1, 0,
+                                 source_tree_->GetLastErrorMessage());
     }
     return false;
   }
@@ -186,6 +188,7 @@ Importer::Importer(SourceTree* source_tree,
                    MultiFileErrorCollector* error_collector)
   : database_(source_tree),
     pool_(&database_, database_.GetValidationErrorCollector()) {
+  pool_.EnforceWeakDependencies(true);
   database_.RecordErrorsTo(error_collector);
 }
 
@@ -195,10 +198,22 @@ const FileDescriptor* Importer::Import(const string& filename) {
   return pool_.FindFileByName(filename);
 }
 
+void Importer::AddUnusedImportTrackFile(const string& file_name) {
+  pool_.AddUnusedImportTrackFile(file_name);
+}
+
+void Importer::ClearUnusedImportTrackFiles() {
+  pool_.ClearUnusedImportTrackFiles();
+}
+
 // ===================================================================
 
 SourceTree::~SourceTree() {}
 
+string SourceTree::GetLastErrorMessage() {
+  return "File not found.";
+}
+
 DiskSourceTree::DiskSourceTree() {}
 
 DiskSourceTree::~DiskSourceTree() {}
@@ -239,9 +254,9 @@ static string CanonicalizePath(string path) {
   }
 #endif
 
-  vector<string> parts;
   vector<string> canonical_parts;
-  SplitStringUsing(path, "/", &parts);  // Note:  Removes empty parts.
+  vector<string> parts = Split(
+      path, "/", true);  // Note:  Removes empty parts.
   for (int i = 0; i < parts.size(); i++) {
     if (parts[i] == ".") {
       // Ignore.
@@ -249,7 +264,7 @@ static string CanonicalizePath(string path) {
       canonical_parts.push_back(parts[i]);
     }
   }
-  string result = JoinStrings(canonical_parts, "/");
+  string result = Join(canonical_parts, "/");
   if (!path.empty() && path[0] == '/') {
     // Restore leading slash.
     result = '/' + result;
@@ -395,8 +410,8 @@ DiskSourceTree::DiskFileToVirtualFile(
 
 bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file,
                                            string* disk_file) {
-  scoped_ptr<io::ZeroCopyInputStream> stream(OpenVirtualFile(virtual_file,
-                                                             disk_file));
+  scoped_ptr<io::ZeroCopyInputStream> stream(
+      OpenVirtualFile(virtual_file, disk_file));
   return stream != NULL;
 }
 
@@ -404,6 +419,10 @@ io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) {
   return OpenVirtualFile(filename, NULL);
 }
 
+string DiskSourceTree::GetLastErrorMessage() {
+  return last_error_message_;
+}
+
 io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
     const string& virtual_file,
     string* disk_file) {
@@ -412,6 +431,8 @@ io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
     // We do not allow importing of paths containing things like ".." or
     // consecutive slashes since the compiler expects files to be uniquely
     // identified by file name.
+    last_error_message_ = "Backslashes, consecutive slashes, \".\", or \"..\" "
+                          "are not allowed in the virtual path";
     return NULL;
   }
 
@@ -429,13 +450,13 @@ io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
 
       if (errno == EACCES) {
         // The file exists but is not readable.
-        // TODO(kenton):  Find a way to report this more nicely.
-        GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file;
+        last_error_message_ = "Read access is denied for file: " +
+                              temp_disk_file;
         return NULL;
       }
     }
   }
-
+  last_error_message_ = "File not found.";
   return NULL;
 }
 

Some files were not shown because too many files changed in this diff